Instant, LocalDateTime, Instant ์ฐจ์ด์ ํ์ฉ
๐ ์๋ก
ํ์ฌ ์ฐ๋ฆฌ ํ์ฌ์์๋ ๋ชจ๋ ๋ ์ง๋ UTC ํ์์กด์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ค.
์ด ๊ณผ์ ์์ ํ์์กด์ ๋ํ ์ดํด๊ฐ ์ ๋๋ก ์กํ ๋ถ๋ค๊ณผ ์กํ์ง ์๋ ๋ถ๋ค์ด ์๋ ๊ฒ ๊ฐ๋ค.
์ฝ๋๋ฅผ ๋ณด๋ฉด, LocalDateTime๊ณผ Instant๊ฐ ์์ฌ์ ์ฌ์ฉ๋๊ณ ์๋ค. ๊ฐ์ ๋ก์ง์์๋ ๋ถ๊ตฌํ๊ณ .
๋๋ ์ ๋๋ก ์กํ์ง ์๋ ์ฌ๋ ์ค ํ ๋ช ์ด๋ค. ํ์์กด์ ๋ํด์ ํ ๋ฒ ์ ๋ฆฌ๋ฅผ ํ์ง๋ง,
์์ง๋ UTC๋ฅผ ์ฑํํ๋ ์ด์ ์ CTO๋๊ป ์ค๋ช ์ ๋ค์์์๋ ๊ณต๊ฐ์ ๋ ๋์ ์ดํด๋ฅผ ์ ๋๋ก ํ์ง ๋ชปํ ์ํฉ์ด๋ค.
์ด๋ฒ ๊ธฐํ์ LocalDateTime๊ณผ Instant๋ก ํ์์กด์ ๋ํ ์ดํด๋๋ฅผ ์กฐ๊ธ ๋ ๋์ผ ๋ชฉ์ ์ด๋ค.
๐ Instant, LocalDateTime, ZoneDateTime ์ฐจ์ด์ ๋ฐ ํน์ง
LocalDateTime
- Java 1.8
- ๋ก์ปฌ ํ์์กด์ ๋ฐ๋ฅธ๋ค.
- ํ์์กด์ ํฌํจํ์ง ์๋๋ค.
- atZone() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ํ์์กด ๋ณํ์ด ๋ถ๊ฐ๋ฅํ๋ค.
Instatnt ํด๋์ค
- Java 1.8
- UTC ํ์์กด์ผ๋ก ์ฌ์ฉ๋๋ฉฐ, 1970๋ 1์ 1์ผ 00:00:00(GMT)๋ถํฐ ๊ฒฝ๊ณผํ ์๊ฐ์ ์ด ๋จ์๋ก ํํํ๋ค.
- ํ์์กด์ ํฌํจํ์ง ์๋๋ค.
- ๋ฌด์กฐ๊ฑด UTC ํ์์กด์ด๋ค.
- atZone() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ค๋ฅธ ํ์์กด์ผ๋ก ๋ณํ์ด ๊ฐ๋ฅํ๋ค.
ZoneDateTime
Java 1.8
ํ์์กด์ ํฌํจํ๋ค.
๊ณต์ ๋ฌธ์๋ฅผ ๋ณด๋ฉด ์๋์ ๊ฐ์ด ํ์์กด์ ํฌํจํ๋ค.A date-time with a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00 Europe/Paris.
๊ฐ ํ์ ์ ํฌ๋งท
์๋ ์ฝ๋๋ ๊ฐ ํ์ ์ ํฌ๋งท์ ๊ฐ๋จํ๊ฒ ์ดํด๋ณด๋ ์ฝ๋์ด๋ค.
- ์ ์ผํ๊ฒ ZoneDateTime๋ง ํ์์กด์ด ์กด์ฌํ๋ค.
- Instant๋ ํ์์กด์ ์์ง๋ง ํญ์ UTC์ด๊ธฐ ๋๋ฌธ์ -9์๊ฐํ์ฌ ๊ณ์ฐ๋๋ค.
- LocalDateTime๋ ํ์์กด์ด ์กด์ฌํ์ง ์๋๋ค.
@Test
void ํ
์คํธ1() {
// given
final DateTimeFormatter dateTimeFormatterISO8601 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx");
String dateTimeString = "2023-01-01T00:00:00+09:00";
ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateTimeString, dateTimeFormatterISO8601);
Instant instant = ZonedDateTime.parse(dateTimeString, dateTimeFormatterISO8601).toInstant();
LocalDateTime localDateTime = LocalDateTime.parse(dateTimeString, dateTimeFormatterISO8601);
// when
System.out.println("================");
System.out.println("zonedDateTime = " + zonedDateTime);
System.out.println("instant = " + instant);
System.out.println("localDateTime = " + localDateTime);
System.out.println("================");
}
// zonedDateTime = 2023-01-01T00:00+09:00
// instant = 2022-12-31T15:00:00Z
// localDateTime = 2023-01-01T00:00
LocalDateTime์ ํ์์กด ์ ์ฉ์ด ๋ถ๊ฐ๋ฅํ๋ค.
LocalDateTime์ ์ฒ์ ์์ฑํ ๋๋ ํ์์กด์ ๋ถ์ฌํ์ฌ ์ ํ ์ ์๋ค.
๋ณด๋ ๋ฐ์ ๊ฐ์ด UTC๋ก ์ ์ฉ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
ํ์ง๋ง ์ดํ ํ์์กด์ ๋ณ๊ฒฝํ๊ณ ์ถ์ด๋ ZoneDateTime์ผ๋ก ๋ณํํด๋ ํ์์กด์ด ์ ์ฉ๋ ์๊ฐ์ธ +9:00์ด ์ ์ฉ๋ ์๊ฐ์ด ์๋๋ค.
- LocalDateTime์ ๋๋ผ๋ณ๋ก ํ์์กด์ ๋ณ๊ฒฝํด์ผ ํ๋ค๋ฉด ์ฌ์ฉํ๊ธฐ ๋ถํธํ๋ค.
// ํ์ฌ ์๊ฐ: 2023-05-28 17:59:00
@Test
void LocalDateTime_ํ์์กด_๋ณํ() {
// given
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("UTC"));
ZonedDateTime localDateTimeToZoneDateTime = localDateTime.atZone(ZoneId.of("Asia/Seoul"));
LocalDateTime zoneDateTimeToLocalDateTime = localDateTimeToZoneDateTime.toLocalDateTime();
// when
System.out.println("============");
System.out.println("localDateTime = " + localDateTime);
System.out.println("localDateTimeToZoneDateTime = " + localDateTimeToZoneDateTime);
System.out.println("zoneDateTimeToLocalDateTime = " + zoneDateTimeToLocalDateTime);
System.out.println("============");
}
// localDateTime = 2023-05-28T08:59:00.506969
// localDateTimeToZoneDateTime = 2023-05-28T08:59:00.506969+09:00[Asia/Seoul]
// zoneDateTimeToLocalDateTime = 2023-05-28T08:59:00.506969
ZoneDateTime์ ํ์์กด ์ ์ฉ์ด ๊ฐ๋ฅํ๋ค.
๋ณด๋ ๋ฐ์ ๊ฐ์ด UTC โ Asia/Seoul๋ก ์ ์ฉ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
// ํ์ฌ ์๊ฐ: 2023-05-28 18:10:00
@Test
void ZoneDateTime_ํ์์กด_๋ณํ() {
// given
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("UTC"));
ZonedDateTime convertTimezone = zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Seoul"));
// when
System.out.println("===============");
System.out.println("zonedDateTime = " + zonedDateTime);
System.out.println("convertTimezone = " + convertTimezone);
System.out.println("===============");
}
// zonedDateTime = 2023-05-28T09:10:24.292591Z[UTC]
// convertTimezone = 2023-05-28T18:10:24.292591+09:00[Asia/Seoul]
Instant๋ ZoneDateTime์ผ๋ก ๋ณํํ๋ฉด ํ์์กด ์ ์ฉ์ด ๊ฐ๋ฅํ๋ค.
// ํ์ฌ ์๊ฐ: 2023-05-28 18:34:00
@Test
void Instant_ํ์์กด_๋ณํ() {
// given
Instant instant = Instant.now();
ZonedDateTime instantToZoneDateTime = instant.atZone(ZoneId.of("Asia/Seoul"));
// when
System.out.println("===============");
System.out.println("instant = " + instant);
System.out.println("instantToZoneDateTime = " + instantToZoneDateTime);
System.out.println("===============");
}
// instant = 2023-05-28T09:34:40.621189Z
// instantToZoneDateTime = 2023-05-28T18:34:40.621189+09:00[Asia/Seoul]
๐ ์ค๋ฌด ํ์ฉ
Instant์ ZoneDateTime
์๋ก ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ UTC๋ก ๊ด๋ฆฌํ๊ณ ์๋ค๊ณ ํ์.
์ ์ฐ์ ํ๋๋ฐ 2023-01-01 04:00์ ๋ฐฐ์น๊ฐ ๋์์ 2022๋ 12์31์ผ์ ์ ์ฐ์ ํ๋ค๊ณ ๊ฐ์ ํ๋ฉด,
2022-12-30 15:00 ~ 2022-12-31 14:59:59์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํด์ ์ ์ฐํด์ผ ํ๋ค.
์ฃผ์ํ ์
instant1์ด ์๋ instant ๋ฐฉ์์ผ๋ก ํ์ฉํด์ผ ํ๋ ๊ฒ์ด๋ค.
instant1 ๋ฐฉ์์ผ๋ก ํ ๊ฒฝ์ฐ ๋ฐฐ์น ์คํ ์๊ฐ์ ๋ฐ๋ผ์ ์กฐํ ๊ธฐ๊ฐ์ด 15์๊ฐ ์๋ 19์๋ก ๋ณ๊ฒฝ๋๊ธฐ ๋๋ฌธ์ด๋ค.Asia/Seoul์ ๋ช ์ํ ์ด์
defaultTimeString์ด +09:00๊ฐ ์๋ +10:00์ผ๋ก ์ ๋ชป ๋์ด์ค๊ฒ ๋ ๊ฒฝ์ฐ์๋ ๋๋นํ๊ธฐ ์ํจ์ด๋ค.
Asia/Seoul๋ก ํ๋ฉด +10:00์ด์ด๋ +9:00๋ก ๋ณํํ์ฌ, 15:00๋ก ์กํ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ฉด ์ง์ ํ์ง ์์ ๊ฒฝ์ฐ 14:00๋ก ๋ณํ๋๊ธฐ ๋๋ฌธ์
์กฐํ ๊ธฐ๊ฐ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
@Test
void d123123dd() {
// given
final DateTimeFormatter dateTimeFormatterISO8601 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx");
String defaultTimeString = "2023-01-01T04:00:00+09:00"; // ์๋ฒฝ 4์ ์ ์ฐ
Instant instant = ZonedDateTime.parse(defaultTimeString, dateTimeFormatterISO8601)
.withZoneSameInstant(ZoneId.of("Asia/Seoul"))
.truncatedTo(ChronoUnit.DAYS)
.toInstant();
long epochMilli = instant.toEpochMilli();
Instant instant1 = ZonedDateTime.parse(defaultTimeString, dateTimeFormatterISO8601)
.withZoneSameInstant(ZoneId.of("Asia/Seoul"))
.toInstant();
long epochMilli1 = instant1.toEpochMilli();
// when
System.out.println("==============");
System.out.println("instant = " + instant);
System.out.println("instant1 = " + instant1);
System.out.println("epochMilli = " + epochMilli);
System.out.println("epochMilli1 = " + epochMilli1);
System.out.println("==============");
}
// instant = 2022-12-31T15:00:00Z
// instant1 = 2022-12-31T19:00:00Z
// epochMilli = 1672498800000
// epochMilli1 = 1672513200000
localDateTime๋ ๊ฐ๋ฅํ๋ค.
๊ทผ๋ฐ ๊ฒฐ๊ตญ ZoneDateTime๊ณผ Instant๋ฅผ ์ด๋ค.
์ค์ ๋ก ํ์์กด์ด ์ ์ฉ๋ ๊ฒ์ ์๋์ง๋ง ๋ง์ง๋ง์ Instant๋ก ๋ณํํ์ฌ ํ์ฉํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฅํ๋ค.
Instant instant3 = LocalDateTime.parse(defaultTimeString, dateTimeFormatterISO8601)
.atZone(ZoneId.of("Asia/Seoul"))
.truncatedTo(ChronoUnit.DAYS)
.toInstant();
Epoch ํ์ฉ
์์ ๊ฐ์ด ํ์ฉํ ์ ์๋ค.
UTC๋ก ๋ฐ์ดํฐ๊ฐ ๊ด๋ฆฌ๋ ๊ฒฝ์ฐ ํ์์กด ์ ํ ์ ๋ฒ๊ฑฐ๋ก์์ ์ค์ด๊ธฐ ์ํด Epoch์ ํ์ฉํ๋ฉด
ํญ์ UTC second์ด๊ธฐ ๋๋ฌธ์ ํจ์ฌ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
๐ Epoch์ด๋?
https://ko.wikipedia.org/wiki/์ ๋์ค_์๊ฐ
UTC ๊ธฐ์ค์ธ 1970๋ 1์ 1์ผ 00:00:00๋ถํฐ์ ๊ฒฝ๊ณผํ ์๊ฐ์ ์ด๋ก ํ์ฐํ์ฌ ์ ์๋ก ํํํ ๊ฒ์ ์๋ฏผํ๋ค.
์ฆ ํ์์กด์ด ์๋ฏธ๊ฐ ์์ด ๋ฌด์กฐ๊ฑด UTC ๊ฒฝ๊ณผ ์๊ฐ์ด๋ค.
์ฃผ์ํ ๊ฒ์ ๋ง์ฝ DB์์ epoch์ FROM_UNIXTIME()์ ์ฌ์ฉํด์ ๋ณํํ๋ฉด,
์ปค๋ฅ์ ๋ ํ์์กด์ ๋ฐ๋ผ์ ๊ฒฐ๊ณผ๊ฐ ๋ค๋ฅด๊ฒ ๋์ค๋ ํผ๋ํ์ง ๋ง์.
์ด๋ FROM_UNIXTIME()๊ฐ DB์ ์ธ์ ํ์์กด์ ๋ฐ๋ผ๊ฐ๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋์ ์์์ ๋ณํํ๋ ๊ฒ์ด๋ค.
์ฝ๋๋ก ํ ์คํธ ํด๋ณด๋ฉด ํฌ๋งทํ ๋ ๋ ์ง๋ ๋ค๋ฅด์ง๋ง epoch์ ๋์ผํ ๊ฒ์ ํ์ธํ ์ ์๋ค.
@Test
void epoch() {
// given
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
long zoneDateTimeEpoch = zonedDateTime.toEpochSecond();
Instant instant = Instant.now();
long instantEpoch = instant.toEpochMilli() / 1000;
// when
System.out.println("=============");
System.out.println("zonedDateTime = " + zonedDateTime);
System.out.println("instant = " + instant);
System.out.println("zoneDateTimeEpoch = " + zoneDateTimeEpoch);
System.out.println("instantEpoch = " + instantEpoch);
System.out.println("=============");
}
// zonedDateTime = 2023-05-28T18:54:34.260566+09:00[Asia/Seoul]
// instant = 2023-05-28T09:54:34.260676Z
// zoneDateTimeEpoch = 1685267674
// instantEpoch = 1685267674
๐ LocalDateTime, ZonedDateTime, Instant ๋ชฉ์
LocalDateTime
- ํ์์กด์ด ํ์์๋ ๊ฒฝ์ฐ ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ๊ธฐ ์ข๋ค.
- ์ฆ, ํน์ ํ์์กด์ ์์กดํ์ง ์๋ ๊ฒฝ์ฐ๋ง ํ์ฉํ๊ธฐ ์ข๋ค.
- ํ์์กด์ ์์กดํ๋ค๋ฉด ์ฌ์ฉํ์ง ์๊ธธ. ์์์ ๋ดค๋ ๊ฒ ์ฒ๋ผ ์๋๋ ๊ฒ์ด ์๋ค.
ZonedDateTime
- ํ์์กด์ ํฌํจํ๊ธฐ ๋๋ฌธ์ ํ์์กด์ ๋ฐ๋ฅธ ์๊ฐ ํํ์ด ๊ฐ๋ฅํ๋ค.
- ํ์์กด์ด ํ์ํ ๊ธ๋ก๋ฒ ์๋น์ค ๊ฐ์ ๊ฒฝ์ฐ ํ์ฉํ๊ธฐ ์ข๋ค.
Instant
- ํ์์กด์ ํฌํจํ์ง ์๊ณ , UTC ๊ธฐ์ค์ผ๋ก ํ์ฉํ ๋ ํธํ๋ค.
ํ .. ์์ง ์ ํํ๊ฒ ์๋ฟ์ง๊ฐ ์๋๋ค.