백엔드

타임존과 날짜 다루기

오늘의 나1 2022. 4. 14. 10:01

SQL로 날짜 변환하기

  • DB의 타임존 구하기
SELECT @@SYSTEM_TIME_ZONE;
  • 타임존 변경하기
# UTC -> Asia/Seoul
SELECT CONVERT_TZ('2022-04-13 00:00:00', 'UTC', 'Asia/Seoul'); # '2022-04-13 09:00:00'
SELECT CONVERT_TZ(CONCAT('2022-04-13', ' ', '00:00:00'), 'UTC', 'Asia/Seoul'); # '2022-04-13 09:00:00'

# Asia/Seoul -> UTC
SELECT CONVERT_TZ('2022-04-13 09:00:00', 'Asia/Seoul', 'UTC'); # '2022-04-13 00:00:00'
SELECT CONVERT_TZ(CONCAT('2022-04-13', ' ', '09:00:00'), 'Asia/Seoul', 'UTC'); # '2022-04-13 00:00:00'
SELECT DATE_FORMAT('2022-04-14 00:00:00', '%Y-%m-%d %H:%i:%s');
  • 현재 시간 특정한 타임존으로 저장하기
SELECT CONVERT_TZ(NOW(), @@SYSTEM_TIME_ZONE, 'Asia/Seoul');

 

LocalDateTime vs ZonedDateTime

  • LocalDateTime vs ZonedDateTime
    • LocalDateTime: 타임존 없는 DateTime
    • ZonedDateTime: 타임존 있는 DateTime. LocalDateTime + ZoneId(타임존)
아래 예제를 실습한 PC의 시간은 2022-04-18T09:00:00+09:00[Asia/Seoul]이다.
  • LocalDateTime 초기화: 설정한 타임존의 yyyy-MM-ddTHH:mm:ss 값이 들어감
// 애플리케이션의 타임존이 Asia/Seoul
// 현재 시간은 2022-04-18T09:00:00[Asia/Seoul]

// 타임존이 없으면, ZoneId.systemDefault()인 Asia/Seoul 값
LocalDateTime ldt = LocalDateTime.now(); 
// 2022-04-18T09:00:00

// 타임존을 설정하면, 타임존으로 설정됨
LocalDateTime ldtAtUtc = LocalDateTime.now(ZoneId.of("UTC")); 
// 2022-04-18T00:00:00
  • LocalDateTime ➡︎ ZonedDateTime: 이 시간은 타임존이 여기야!
    • LocalDateTime의 yyyy-MM-ddTHH:mm:ss 값은 그대로 + 타임존만 붙음 
// 애플리케이션의 타임존이 Asia/Seoul
// 현재 시간은 2022-04-18T09:00:00[Asia/Seoul]

// 2022-04-18T09:00:00 + 타임존
LocalDateTime ldt = LocalDateTime.now(); // 2022-04-18T09:00:00
ldt.atZone(ZoneId.of("Asia/Seoul")); // 2022-04-18T09:00:00+09:00[Asia/Seoul]
ldt.atZone(ZoneId.of("UTC")); // 2022-04-18T09:00:00Z[UTC]

// 2022-04-18T00:00:00 + 타임존
LocalDateTime ldtAtUtc = LocalDateTime.now(ZoneId.of("UTC")); // 2022-04-18T00:00:00
ldtAtUtc.atZone(ZoneId.of("Asia/Seoul")); // 2022-04-18T00:00:00+09:00[Asia/Seoul]
ldtAtUtc.atZone(ZoneId.of("UTC")); // 2022-04-18T00:00:00Z[UTC]
  • ZonedDateTime 초기화: 설정한 타임존의 yyyy-MM-ddTHH:mm:ss 값 + 타임존
ZonedDateTime zdt = ZonedDateTime.now(); // 2022-04-18T09:00:00+09:00[Asia/Seoul]
ZonedDateTime zdtAtUtc = ZonedDateTime.now(ZoneId.of("UTC")); // 2022-04-18T00:00:00Z[UTC]
  • ZonedDateTime ➡︎ LocalDateTime: 타임존만 쏙 빠짐
ZonedDateTime zdt = ZonedDateTime.now(); // 2022-04-18T09:00:00+09:00[Asia/Seoul]
zdt.toLocalDateTime(); // 2022-04-18T09:00:00

ZonedDateTime zdtAtUtc = ZonedDateTime.now(ZoneId.of("UTC")); // 2022-04-18T00:00:00Z[UTC]
zdtAtUtc.toLocalDateTime(); // 2022-04-18T00:00:00
  • 현재 시간 구하기
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime); 
System.out.println(zonedDateTime.getZone()); // System Default

zonedDateTime = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println(zonedDateTime);
System.out.println(zonedDateTime.getZone()); // America/New_York

 

LocalDateTime, ZonedDateTime을 MyBatis의 SQL로 보내기

  • MyBatis Mapper 코드
<select id="selectLocaldatetime" parameterType="map" resultType="string">
    SELECT #{localDateTime};
</select>
<select id="selectZoneddatetime" parameterType="map" resultType="string">
    SELECT #{zonedDateTime};
</select>
  • 코드 실행 시, ZonedDateTime은 타임존이 시스템 기본 타임존으로 변경된다.
    • ZoneDateTime::withZoneSameTime(ZoneId.systemDefault())의 yyyy-MM-ddTHH:mm:ss 으로 변경
readMapper.selectLocaldatetime(LocalDateTime.now()); 
# SELECT '2022-04-18T09:00:00'; -> Asia/Seoul

readMapper.selectLocaldatetime(LocalDate.now().atStartOfDay()); 
# SELECT '2022-04-18T00:00:00'; -> Asia/Seoul

readMapper.selectZoneddatetime(ZonedDateTime.now());
# SELECT '2022-04-18T09:00:00'; -> Asia/Seoul

readMapper.selectZoneddatetime(ZonedDateTime.now(ZoneId.of("UTC")));
# SELECT '2022-04-18T09:00:00'; -> Asia/Seoul

readMapper.selectZoneddatetime(ZonedDateTime.now(ZoneId.of("America/New_York")));
# SELECT '2022-04-18T09:00:00'; -> Asia/Seoul

 

출처