날짜와 시간
01_ 날짜와 데이터 시간
* java.time.* 패키지 사용 (import)
- 타임존 : [ Asia/Seoul ] 과 같은 지역 정보, 세계의 각 타임존은 UTC(협정 세계시)로부터의 시간 차이로 정의
>> UTC : 1970년 01월 01일 자정을 0밀리초로 설정하여 기준을 삼아 그 후로 시간의 흐름을 밀리초로 계
- 오프셋 (offSet) : 처음 주어진 요소나 지점까지의 변위차를 나타냄
- 일광절약시간(DST) : 일광 절약 시간이 적용 되는 경우, 타임존 차이가 변할 수 있음
1) LocalDate : 날짜만 표현 할 때 ex) 2013-11-21
2) LocalTime : 시간만을 표현 할 때 ex) 08:20:30.213
3) LocalDateTime : 위의 LocalDate, LocaTime 을 합한 것 (날짜와 시간)
- 시차 정보가 없기 때문에 다른 위치에 있는 서버에서 동시 저장 시 다른 시간으로 저장
- 같은 시간이라는 것을 알 수 없음
※ 모든 날짜 객체는 불변이므로 변경 발생 시 새로운 객체 생성 후 그 객체에 반환 값을 받아 출력
* 계산
- .plusDays(10) = 특정 날짜에 +10일 더함
ex) 코드 참조 (불변 객체이기 때문에 새로운 ofdate = ofdate.plusDays(10) 객체 생성)
public class LocalDateMain {
public static void main(String[] args) {
LocalDate nowdate = LocalDate.now();
System.out.println("오늘 날짜 : " + nowdate);
LocalDate ofdate = LocalDate.of(2013,11,21);
System.out.println("지정 날짜 : " + ofdate);
// 계산 불변
// ofdate의 경우 enum 이기 때문에 반환값 ofdate = ofdate.plusDays() 를 통해 새로운 객체를 생성 해서 10일 더한 날짜를 출력한다.
ofdate = ofdate.plusDays(10);
System.out.println("지정 날짜 + 10일 : " + ofdate); // 새로운 객체 ofdate
}
}
(ofdate 의 새로운 객체 생성)
4) 날짜 비교 < isEqual() vs equal() >
5) ZondDateTime
- "Asia/Seoul" 같은 타임존 안에는 일광 절약 시간제에 대한 정보와 UTC + 9:00 와 같은 UTC로 부터 시간 차이인 오프셋 정보를 모두 포함 (시차 및 지역 정보 확인 가능)
6) OffsetDateTime
- ZondDateTime 과 유사하지만 타임존 정보는 안나옴 [Asia/Seoul]
7) Instant
- Instant 내부에는 초(sec) 데이터만 들어 있음 (나노 sec 포함)
- UTC 기준, 시간대(고정)에 영향을 받지 않음
- 시간 계산 및 비교가 명확하고 일관성이 있음
>> 날짜와 시간에 대한 계산 필요 시 LocalDateTime 및 ZondDateTime 사용
>> 초(sec) 단위에 대한 계산 필요 시 Instant 사용
참고) Epoch 시간 (UTC 기준)
- 1970년 01월 01일 이후로 현재까지 경과한 전체 초(sec) 의 수로, 시간대에 영향을 받지 않는 절대적인 시간 표현 방식
(Instant 는 이 Epoch 시간을 다루는 클래스이다)
8) Duration(시간), Period(날짜) - 시간의 간격(기간)을 표현하는데 사용
Duration 주요 메서드에서 Hours 와 Minutes() 만 to 를 사용하는 이유 = 실제 자바의 Duration 클래스에는 Seconds 와 Nano에 대한 정의만 final 로 정의 되어 있기 때문에 Hours 와 Minutes 는 사용자가 직접 계산을 해야 하기 때문 to 사용
ex)
- 별도 : .toMinutes() 와 .toMinutesPart() 차이 코드 참조
public static void main(String[] args) {
Duration duration = Duration.ofMinutes(30);
System.out.println("duration = " + duration);
LocalTime lt = LocalTime.of(1, 0);
System.out.println("lt = " + lt);
// 계산에 사용
LocalTime plusTime = lt.plus(duration);
System.out.println("plusTime = " + plusTime);
LocalTime start = LocalTime.of(9, 0);
LocalTime end = LocalTime.of(10, 0);
Duration between = Duration.between(start, end);
System.out.println("차이 : " + between.getSeconds());
// between.toMinutes : 전체 60분을 돌려주는 것
// between.toMinutesParts : toHours(시간)을 빼고 남은 분(min) 을 되돌려 줌
System.out.println("근무 시간 : " + between.toHours() + "시간 : " + between.toMinutesPart() + "분");
}
}
>> 결과 출력
.toMinutes() - 근무 시간 : 1시간 60분
.toMinutesPart() - 근무 시간 :1시간 0분
02_ 날짜와 시간의 핵심 인터페이스
1) TemporalAccessor 인터페이스 (읽기)
- 날짜와 시간을 읽기 위한 기본 인터페이스
2) Temporal 인터페이스 (읽기, 쓰기)
- TemporalAccessor 의 하위 인터 페이스
- 날짜와 시간을 읽고 쓰기 위한 인터페이스
3) TemporalAmount 인터페이스 (시간의 간격 더하기 빼기 등)
- 특정 날짜에 일정 기간을 더하거나 빼는데 사용
시간의 단위와 시간 필드 - 시간의 단위(Unit)와 필드(Field)를 구성하는 핵심 인터페이스 두 가지
4) TemporalUnit(상위 인터페이스), ChronoUnit (TeporalUnit의 구현체 ,enum Type)
- ChronoUnit : 다양한 시간 단위 제공
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
public class ChronoUnitMain {
public static void main(String[] args) {
ChronoUnit[] values = ChronoUnit.values();
for (ChronoUnit value : values) {
System.out.println("value = " + value);
}
System.out.println("ChronoUnit.HOURS = " + ChronoUnit.HOURS);
System.out.println("HOURS.duration = " + ChronoUnit.HOURS.getDuration().getSeconds());
System.out.println("ChronoUnit.DAYS = " + ChronoUnit.DAYS);
System.out.println("DAYS.duration = " + ChronoUnit.DAYS.getDuration().getSeconds());
// 차이 구하기
LocalTime lt1 = LocalTime.of(1, 10, 0);
LocalTime lt2 = LocalTime.of(1, 20, 0);
long secondsBetween = ChronoUnit.SECONDS.between(lt1, lt2);
System.out.println("secondsBetween = " + secondsBetween);
long minutesbetween = ChronoUnit.MINUTES.between(lt1, lt2);
System.out.println("minutesbetween = " + minutesbetween);
}
}
5) TemporalField (날짜와 시간의 특정 부분, enum Type)
- 특정 날짜에서 원하는 필드의 데이터를 조회
import java.time.temporal.ChronoField;
public class ChronoFieldMain {
public static void main(String[] args) {
ChronoField[] values = ChronoField.values();
for (ChronoField value : values) {
System.out.println("value = " + value + ", range = " + value.range());
}
System.out.println("ChronoField.MONTH_OF_YEAR.range() = " + ChronoField.MONTH_OF_YEAR.range()); // result : 1 - 12
System.out.println("ChronoField.DAY_OF_MONTH.range() = " + ChronoField.DAY_OF_MONTH.range()); // result : 1 - 28/31
}
}
03_ isSupported (사용자가 가져오고자 하는 날짜 데이터 출력 가능 여부 확인)
import java.time.LocalDate;
import java.time.temporal.ChronoField;
public class IsSupportedMain2 {
public static void main(String[] args) {
LocalDate now = LocalDate.now();
// LocalDate 에서 SECOND_OF_NINUTE 를 사용 할 수 있는지 판단하는 isSupported 메서드 실행
boolean supported = now.isSupported(ChronoField.SECOND_OF_MINUTE);
System.out.println("supported = " + supported);
// 조건문으로 가능 여부에 따른 출력 결과 작성
if (supported) {
int minute = now.get(ChronoField.SECOND_OF_MINUTE);
System.out.println("minute = " + minute);
} else {
System.out.println("쓰지마세요");
}
}
}
04_ 날짜 및 시간 문자열 파싱과 포맷팅
- 포맷팅(format) : 날짜와 시간 데이터를 원하는 포맷의 문자열로 변경 하는 것 (Date -> String)
- 파싱(parse) : 문자열을 날짜와 시간 데이터로 변경 하는 것 (String -> Date)
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class FommattingMain2 {
public static void main(String[] args) {
// formatter 포맷팅 날짜와 시간을 문자로
LocalDateTime now = LocalDateTime.of(2024, 12, 31, 13, 30, 59);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 원하는 포맷 형식 지정 .ofPattern();
String formattedDateTime = now.format(formatter); //
System.out.println("날짜와 시간 포맷팅 : " + formattedDateTime);
System.out.println(now); // ISO 국제 표준 날짜 시간
// parse : 문자를 날짜와 시간으로
String dataTimeString = "2030-01-01 11:30:00";
LocalDateTime parsedDateTime = LocalDateTime.parse(dataTimeString, formatter); // 원하는 파싱 형식 지정 .parse();
System.out.println("parsedDateTime = " + parsedDateTime);
}
}
>> 결과 코드