Java 8 LocalDateTime vs Instant 어떤 상황에서 쓰는게 적합한가?
들어가기 전에
- 본 글은 세션 공유용 자료이며
LocalDateTime
,Instant
의 개념에 관한 짧은 글이 아니므로 양해 부탁드립니다.
포스팅 계기
- 최근 새 회사(이커머스 도메인)에 이직하게 되었고 코프링(코틀린 + 스프링)기반 프로젝트를 진행하고 있었다.
- 프로젝트를 살펴보던 중 시간 관련 데이터들을 DB에
LocalDateTime
로 넣고 있었다.Instant
클래스가 아닌LocalDateTime
로 넣는 이유가 궁금해서 팀 내에 공유할 겸 오랜만에 포스팅하게 되었다.
그냥 LocalDateTime 쓰면 안되나요?
독자들은 LocalDateTime
이나 Instant
아무거나 쓰면 안 되나? 이런 궁금증이 들 수 있다. LocalDateTime
클래스는 개인 프로젝트를 진행할 때 시간 관련 Type
으로 사용했던 경험이 있을 것이다. 필자 또한 개인 프로젝트 하면서 해당 클래스를 사용했었다. 정확히 Instant
클래스를 알기 전까지 사용했다. (전 회사에서는 Instant
클래스를 사용했고 현 회사에서는 LocalDateTime
을 사용하고 있었기에 의문이 들었다.)
LocalDateTime
, LocalDate
, LocalTime
간단한 사용법들은 이전글 에서 포스팅 하였고 개념글 위주로 LocalDateTime
이 좋은지 Instant
가 좋은지 더 깊게 공부해 보았고 포스팅하려고 한다.
(혹시나 Java 8
이상 사용 중이고 Date
나 Calandar
클래스를 사용하고 있다면 지양하는 것을 추천한다.)
아래 링크 참고 하길 바란다
- [Java] Date와 Calendar 클래스
- [Java] Date, Calendar클래스가 왜 Deprecated됐는지?
- [Java] Java 8에 추가된 LocalDate, LocalTime, LocalDateTime (간단하게 사용법들을 작성해놓았기에 개념 설명은 본 글에서 진행)
Instant
위 사진은 이해를 돕기 위한 이미지이다. (날짜 + 시간 + UTC)
Instant
클래스는 단어의 의미와 같이 순간, 즉시 를 의미한다.- 컴퓨팅을 하기 위해
Timestamp
로 기술적인 표현을 한 것이다.- 즉, 인간보다는 기계에 친화적이다.
long
형태로Unix Timestamp
를 저장하기 때문에 연산이 빠르다.Unix Timestamp
를 사용하면 되지 않나? 라는 의문을 가진 독자가 있을 것이다.Unix Timestamp
는 2038년 문제가 있다. 1970년 1월 1일 자정에서부터 2147483647 초가 지난2038년 1월 19일 화요일 03:14:07 UTC
까지 표현이 가능하다. 이것을 보완한 것이Instant
클래스이다
-
private static final long MIN_SECOND = -31557014167219200L; private static final long MAX_SECOND = 31556889864403199L;
- 지원할 수 있는 범위는 아래와 같다.
MIN_SECOND
=-10000000-01-01T00:00Z
MAX_SECOND
=1000000000-12-31T23:59:59.99999999Z
- 현재 순간을 찍으려면 아래와 같이 객체를 생성하면 된다.
-
Instant now = Instant.now(); println(now); // 2022-08-08T16:09:17.105081Z -- 2022년 08월 09일 01시 09분 17초
- 나노초까지 표현이 가능하다.
- 뒤에 Z를 표현하는 것을 볼 수 있다.
- ISO_8601은 날짜와 시간과 관련된 데이터 교환을 다루는 국제 표준이며 링크를 참고하면 된다.
- 앞에 “인간보단 기계에 친화적이라고 했는데 읽기 편한데?”라고 생각할 수 있다.
- Timestamp는 본래 long 타입이다.
toString()
을 재정의하여DateTimeFormatter
로 읽기 쉽게 해준 것이다.
- Timestamp는 본래 long 타입이다.
- 어떻게 UTC 기반으로 타임을 찍는가?
-
public static Instant now() { return Clock.currentInstant(); } public abstract class Clock { private static final long OFFSET_SEED = System.currentTimeMillis() / 1000 - 1024; private static long offset = OFFSET_SEED; // 시스템의 현재 시간을 가져온다 나노초로 가져오는 것을 밀리초로 표현해준다. static Instant currentInstant() { long localOffset = offset; long adjustment = VM.getNanoTimeAdjustment(localOffset); // 밀리초를 나노초로 변환해서 가져온다 ... return Instant.ofEpochSecond(localOffset, adjustment); } }
-
LocalDateTime
LocalDateTime
은 날짜 + 시간 정보를 가지고 있다.Timezone
이 없는 것을 볼 수 있다.LocalDateTime
은 인간에게 친화적인 타입이다.Timezone
이 없는데Instant
와 같이UTC
로 넣는게 아닌가?라는 생각을 할 수 있다.LocalDateTime
은 어떻게 시간을 나타내는지 보자-
LocalDateTime now = LocalDateTime.now(); println(now); // 2022-08-09T01:09:17.113332 2022년 08월 09일 01시 09분 17초
-
LocalDateTime
은 현재 로컬 시간에 맞춰서 시간을 표현하고 있다.- 내부 코드를 살펴보자
-
public final class LocalDateTime { public static LocalDateTime now() { return now(Clock.systemDefaultZone()); } } public static Clock systemDefaultZone() { // 시스템의 ZoneId를 가져온다 return new SystemClock(ZoneId.systemDefault()); } public static LocalDateTime now(Clock clock) { Objects.requireNonNull(clock, "clock"); final Instant now = clock.instant(); // ZoneId를 기반으로 Offset 정보를 가져온다. ZoneOffset offset = clock.getZone().getRules().getOffset(now); return ofEpochSecond(now.getEpochSecond(), now.getNano(), offset); } public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) { Objects.requireNonNull(offset, "offset"); NANO_OF_SECOND.checkValidValue(nanoOfSecond); long localSecond = epochSecond + offset.getTotalSeconds(); long localEpochDay = Math.floorDiv(localSecond, SECONDS_PER_DAY); int secsOfDay = Math.floorMod(localSecond, SECONDS_PER_DAY); LocalDate date = LocalDate.ofEpochDay(localEpochDay); LocalTime time = LocalTime.ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + nanoOfSecond); return new LocalDateTime(date, time); }
- 인스턴스의
Timezone
기반으로 Offset을 생성한 후 현재 시점 기준으로LocalDate
,LocalTime
객체를 생성 후LocalDateTime
을 생성 해주는 것을 볼 수 있다.
-
- 내부 코드를 살펴보자
LocalDateTime 을 사용 했을 때 문제점?
LocalDateTime
코드를 살펴보았으니 한 가지 추론을 해보자 글로벌 서비스를Seoul(Asia/Seoul)
,LA(America/Los_Angeles)
,Tokyo(Asia/Tokyo)
에 운영하고 있다고 가정하면 각각Region
마다 서버를 둘 것이고 타임존이 각각 다를 것이다. 각 인스턴스에서LocalDateTime.now()
로 시간을 입력한다고 해보자 그럼 DB에는 어떻게 들어갈 것인가? 인스턴스의Timezone
을UTC
로 설정해 주지 않는 이상 각각Timezone
에 맞춰 데이터가 들어갈 것이다.
어떤 상황에 사용하는 것이 적합한가?
Instant 클래스를 사용하기 적합한 곳
- Timestamp를 UTC 형식으로 저장하는 곳 즉 DB, 벡엔드 비즈니스 로직, 데이터 교환, 직렬화 시나리오에 적합하다. (연산하기 쉽기 때문)
- 글로벌 런칭한 서비스 비즈니스 앱 개발 시
Instant
나ZonedDateTime
클래스 (ZoneId
+Instant
)를 많이 사용한다.
LocalDateTime 을 사용하기 적합한 곳
- 글로벌 서비스가 아닌 단일 리전 서비스 일 때(타임존 X)
- 즉, 특정 날짜와 시간을 여러 리전에서 적용하려는 경우
- FrontEnd Service, 즉 Display(View) 에 좋다고 한다.
개인적인 견해
- 글로벌 서비스일 경우
LocalDateTime
보다는Instant
나ZonedDateTime
을 사용하는 것이 좋다고 생각한다. Instant
클래스를 사용자 입장에서long
형태로 받기 때문에 읽기 힘들다고 할 수 있는데toString()
으로 재정의가 되어있고 Converting 하거나Serialize
하여 보내주면 된다고 생각한다.UTC
기반으로 DB에 넣어주고Timezone
기반으로 보여주면 될 것 같다고 생각이 든다.- User의
Region
, User가 속한 그룹의Region
들이 다르고Timezone
을 다양하게 가져갈 수 있기 때문에 적절하게 사용하면 된다고 생각
- User의
후기
- 이직 후 첫 세션 공유 자리이므로 준비하는 시간이 생각보다 오래 걸렸지만 재미 있었다.
Reference
- https://stackoverflow.com/questions/32437550/whats-the-difference-between-instant-and-localdatetime
- https://stackoverflow.com/questions/39586311/java-8-localdatetime-now-only-giving-precision-of-milliseconds
- https://stackoverflow.com/questions/44965545/best-practices-with-saving-datetime-timezone-info-in-database-when-data-is-dep
- https://www.alibabacloud.com/blog/performance-issues-related-to-localdatetime-and-instant-during-serialization-operations_595605?spm=2c41.13786565.0.0
'Java > 개념' 카테고리의 다른 글
Java 8 ZonedDateTime vs OffsetDateTime 어떤 상황에서 쓰는게 적합한가? (0) | 2022.08.19 |
---|---|
Java 메모리 최적화가 어떻게 되는지 과정 (0) | 2021.02.25 |
JVM 동적 클래스 로딩 (0) | 2021.02.24 |
[Java] Java 8에 추가된 LocalDate, LocalTime, LocalDateTime (0) | 2020.11.02 |
[Java] Date, Calendar클래스가 왜 Deprecated됐는지? (0) | 2020.11.02 |