본문 바로가기

Java

Java/Kotlin에서 Instant와 LocalDateTime 사용 시 주의점

개요

Java 8부터 도입된 java.time 패키지는 날짜와 시간을 다룰 때 직관적이고 안전한 방법을 제공한다.

이 중 Instant와 LocalDateTime은 자주 사용되는 클래스이지만, 특성을 잘 알고 사용하지 않으면 사용 중에 예상치 못한 문제가 발생할 수 있다.

Instant와 LocalDateTime의 정의

  • Instant: 특정 시점(타임스탬프)을 나타내는 클래스이다. UTC(협정 세계시) 기준의 시간을 밀리초 혹은 나노초 단위로 저장하며, 전 세계에서 동일한 기준 시간을 유지하는 데 적합하다. Instant는 시간대 정보를 포함하지 않으며, UTC 기준으로 동작한다.
  • LocalDateTime: 특정 시간대를 고려하지 않은 날짜 및 시간을 나타내는 클래스이다. 즉, 시간대 정보 없이 연-월-일 시-분-초 값을 저장하며, 이를 특정 시간대로 변환하려면 ZoneId를 명시적으로 지정해야 한다.

문제 상황

서비스에서 데이터베이스에 저장되는 날짜와 시간 값은 KST 기준의 값을 저장하고 있다. 하지만 몇몇 테이블에 대한 엔티티를 작성할 때 LocalDateTime 대신 Instant 타입으로 지정하여 사용하는 경우가 있었다. 이 경우 실제 시간은 KST 로컬타임인데도, 애플리케이션에서 이를 UTC로 인식하는 문제가 발생했다. 그 결과, 시간을 클라이언트에 반환할 때 Z(UTC) 표시가 붙어, 프론트엔드에서 이를 UTC로 해석하고 9시간을 더해 잘못된 시간이 표시되는 문제가 발생했다.

발생한 문제 요약

  • DB에는 LocalDateTime(KST) 기준으로 저장됨
  • 서비스에서 해당 값을 Instant 타입으로 변환하여 사용함
  • Instant는 UTC 기준으로 동작하므로, KST 시간을 UTC로 잘못 해석하여 Z를 붙여 반환함
  • 프론트엔드는 이를 UTC로 처리하여 9시간을 추가함 → 실제보다 9시간 늦은 시간이 표시됨

해결 방법

이 문제를 해결하기 위해 엔티티 작성 시 Instant 대신 LocalDateTime을 사용하여 KST 시간대를 유지하는 방식으로 변경하였다.

[참고]

1. Instant와 LocalDateTime 변환 시 시간대 고려하기

import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId

fun main() {
    val instant = Instant.now() // 시스템의 현재 시각을 UTC 기준으로 반환함
    val zoneId = ZoneId.of("Asia/Seoul")
    val localDateTime = instant.atZone(zoneId).toLocalDateTime()

    println("Instant: $instant")
    println("LocalDateTime: $localDateTime")
}

✅ Instant를 LocalDateTime으로 변환할 때는 반드시 ZoneId를 지정해야 한다.

2. LocalDateTime을 Instant로 변환하기

import java.time.LocalDateTime
import java.time.ZoneId
import java.time.Instant

fun main() {
    val localDateTime = LocalDateTime.now()
    val zoneId = ZoneId.of("Asia/Seoul")
    val instant = localDateTime.atZone(zoneId).toInstant()

    println("LocalDateTime: $localDateTime")
    println("Instant: $instant")
}

✅ LocalDateTime을 Instant로 변환할 때는 ZoneId를 설정해야 올바른 UTC 시간이 유지된다.

정리

  • Instant는 특정 시점을 UTC 기준으로 저장하며, LocalDateTime은 시간대 정보를 포함하지 않으므로 변환 시 주의가 필요하다.
  • DB에서 KST 기준으로 저장된 시간을 UTC 기준인 Instant 타입으로 변환하면 Z(UTC) 표기가 붙는 문제가 발생할 수 있다.
  • LocalDateTime을 직접 사용하면 KST 시간대를 유지하면서 불필요한 변환 문제를 방지할 수 있다.
  • Instant ↔ LocalDateTime 변환 시 반드시 ZoneId를 설정해야 한다.
  • 일부 시스템에서는 전역 시간 기준의 정확한 타임스탬프가 필요할 수 있다. 분산 시스템에서 이벤트 순서 보장, 로그 기록 등 UTC 기준이 필요한 경우는 Instant 타입을 적절히 사용해야 한다.

'Java' 카테고리의 다른 글