java.time 패키지를 공부하는 중, Instant 클래스에 대해 처음 알게되었다.
평소 프로젝트를 할 때는 LocalDateTime
을 사용했는데, Instant
를 사용해야 좋은 경우는 무엇이 있는지 궁금증이 생겼다.
살펴보던 와중 LocalDateTime
을 엔티티 칼럼으로 지정한 필드는 DB에 무슨 형식으로 저장했더라... 하고 살펴보니 냅다 문자열로 저장했거나 datetime 형식이다. datetime 형식은 SQL 표준에 맞지않고 정확도가 떨어져 공식문서에서는 권장하지 않는다고 하니 다음번에 프로젝트를 할 땐 DB쪽 형식도 제대로 찾아보고 설정해야겠다 😅ㅎ
java.time 패키지의 핵심 클래스
날짜와 시간을 하나로 표현하는 Calendar
클래스와 달리, java.time
패키지에서는 날짜와 시간을 별도의 클래스로 분리해 놓았다.
LocalDate (날짜) + LocalTime (시간) → LocalDateTime (날짜&시간)
LocalDateTime + 시간대 → ZonedDateTime
Instant 클래스
Instant
는 날짜와 시간을 초단위(정확히는 나노초)로 표현한다. 날짜와 시간을 초단위로 표현한 값을 타임스탬프(time-stamp)라고 부르는데, 이 값은 날짜와 시간을 하나의 정수로 표현할 수 있으므로 날짜와 시간의 차이를 계산하거나 순서를 비교하는데 유리해서 데이터베이스에 많이 사용된다.
인간보다는 기계에 친화적이다.
Instant
는 에포크 타임(EPOCH TIME, 1970-01-01 00:00:00 UTC)부터 경과된 시간을 나노초 단위로 표현한다.
사람에겐 불편하지만, 단일 진법으로만 다루기 때문에 계산하기 쉽다. long 형태로 Unix Timestamp를 저장하기 때문에 연산이 빠르다.
Instant now = Instant.now();
Instant now2 = Instant.ofEpochSecond(now.getEpochSecond()); //나노초는 0으로 설정됨
Instant now3 = Instant.ofEpochSecond(now.getEpochSecond(), now.getNano());
System.out.println("epochSec :" + now2.getEpochSecond()); //epochSec :1673939166
System.out.println("nano 1 :" + now.getNano()); //nano 1 :722188500
System.out.println("nano 2 :" + now2.getNano()); //nano 2 :0
System.out.println("nano 3 :" + now3.getNano()); //nano 3 :722188500
System.out.println("밀리초 :" + now.toEpochMilli()); //밀리초 :1673939166722
long toEpochMilli()
- 오라클 데이터베이스의 타임스탬프(timestamp)처럼 밀리초 단위의 EPOCH TIME을 필요로 하는 경우를 위한 메서드. (1밀리초 = 1000000나노초)
Instant
는 항상 UTC(+00:00)를 기준으로 하기 때문에, LocalTime
과 차이가 있을 수 있다. 예를 들어 한국은 시간대가 '+09:00'이므로 Instant
와 LocalTime
간에는 9시간의 차이가 있다. 시간대를 고려해야하는 경우 OffsetDateTime
을 사용하는 것이 더 나은 선택일 수 있다.
Instant와 Date간의 변환
Instant
는 기존의 java.util.Date
를 대체하기 위한 것이며, JDK1.8부터 Date에 Instant
로 변환할 수 있는 새로운 메서드가 추가되었다.
static Date from(Instant instant) // Instant -> Date
Instant toInstant() // Date -> Instant
LocalDateTime 과 ZonedDateTime
LocalDateTime
은 날짜 + 시간 정보를 가지고 있다. Timezone
이 없으며, 현재 로컬 시간에 맞춰서 시간을 표현한다.
LocalDateTime
에 시간대(time-zone)를 추가하면, ZonedDateTime
이 된다. java.time
패키지에서는 ZoneId
라는 클래스를 사용하여 시간대를 다룬다. ZoneId
는 일광 절약시간(DST, Daylight Saving Time)을 자동적으로 처리해준다.
LocalDate
에 시간 정보를 추가하는 atTime()
을 쓰면 LocalDateTime
을 얻을 수 있는 것처럼, LocalDateTime
에 atZone()
으로 시간대 정보를 추가하면, ZonedDateTime
을 얻을 수 있다.
cf) 사용가능한 ZoneId
의 목록은 ZoneId.getAvailableZoneIds()
로 얻을 수 있다.
LocalDateTime dateTime = LocalDateTime.of(2023, 01, 17, 12, 34, 56);
ZoneId zid = ZoneId.of("Asia/Seoul");
ZonedDateTime zdt = dateTime.atZone(zid);
System.out.println(zdt); //2023-01-17T12:34:56+09:00[Asia/Seoul]
ZonedDateTime zdt2 = LocalDate.now().atStartOfDay(zid);
System.out.println(zdt2); //2023-01-17T00:00+09:00[Asia/Seoul]
ZoneId nyId = ZoneId.of("America/New_York");
ZonedDateTime nyTime = ZonedDateTime.now().withZoneSameInstant(nyId);
System.out.println(nyTime); //2023-01-17T02:33:13.908404-05:00[America/New_York]
ZoneOffset 과 OffsetDateTime
UTC로부터 얼마만큼 떨어져 있는지를 ZoneOffSet
으로 표현한다. ZonedDateTime
은 ZoneId
로 구역을 표현하는데, ZoneId
가 아닌 ZoneOffset
을 사용하는 것이 OffsetDateTime
이다.
ZoneId vs. ZoneOffset
ZoneId
는 일광절약시간처럼 시간대와 관련된 규칙들을 포함하고 있으나 ZoneOffset
은 단지 시간대를 시간의 차이로만 구분한다. 컴퓨터에게 일광절약시간처럼 계절별로 시간을 더했다 뺏다하는 것과 같은 행위는 위험하기 그지없다. 아무런 변화 없이 일관된 시간체계를 유지하는 것이 더 안전하다.
결론
같은 지역 내의 컴퓨터간에 데이터를 주고받을 때, 전송시간을 표현하기에 LocalDateTime 이면 충분하겠지만, 서로 다른 시간대에 존재하는 컴퓨터간의 통신에는 OffsetDateTime이 필요하다.
Reference
'JAVA' 카테고리의 다른 글
[JAVA] 다형성과 형변환 (상속과 참조변수, Up-casting, Down-casting) (0) | 2023.01.03 |
---|---|
[JAVA] 가변인자(varargs)와 오버로딩 (0) | 2023.01.03 |
[JAVA] 변수와 메서드 (선언위치, JVM 메모리구조, static과 인스턴스) (0) | 2023.01.03 |
[JAVA] empty()와 isEmpty() (0) | 2022.07.28 |
[JAVA] 컬렉션 프레임웍(Collections Framework) (0) | 2022.07.28 |
댓글