์๋ฐ ๋ ์ง ๋ฐ ์๊ฐ ํฌ๋งท
์ฌ๋ฌ ๊ตญ๊ฐ๋ฅผ ๋์์ผ๋ก ํด์ผํ๋ ์๋น์ค๋ฅผ ๋ง๋ค์ด๊ฐ๊ฒ ๋๋ ๊ฒฝ์ฐ ์ธ์ด ๋ฟ๋ง ์๋๋ผ ์๊ฐ์ ๋ค๋ฃจ๋ ๊ฒ๋ ์ค์ํฉ๋๋ค. ๋จ์ํ๊ฒ ๋งํด์ ํ๊ตญ์์ ์๋น์ค๋ฅผ ์ ๊ณตํ๋ค๊ณ ํด์ ํ๊ตญ ์๊ฐ์ผ๋ก ๋ชจ๋ ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋ ๊ฒ์ ์ข์ ๋ฐฉ์์ด ์๋๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก๋ UTC๋ผ๊ณ ํ๋ ์ธ๊ณ ํ์ ์๊ฐ์ ๊ธฐ์ค์ผ๋ก ์๊ฐ์ ์ ์ฅํด์ผํฉ๋๋ค. PostgreSQL๊ณผ ๊ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์๋ Timestamp๋ฅผ ์ ์ฅํ๊ฒ ๋๋ ๊ฒฝ์ฐ ๋ด๋ถ์ ์ผ๋ก๋ UTC๋ก ์ ์ฅ๋ฉ๋๋ค. ๋ฐ๋ผ์, 2022๋
3์ 19์ผ 12์ ๋ผ๋ ์๊ฐ์ 2022๋
3์ 19์ผ 03์
๋ก ์ ์ฅ๋๋๊ฒ์ด์ฃ .
์ ํ๋ฆฌ์ผ์ด์ ๋ฟ๋ง ์๋๋ผ ์๋ฒ ๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ชจ๋ UTC๋ก ์ค์ ํ์ฌ ์ฌ์ฉํ๋๊ฒ ์ผ๋ฐ์ ์ ๋๋ค. ์๋ฅผ ๋ค์ด, ์๋ง์กด ์น ์๋น์ค์ EC2๋ ํ๊ตญ ๋ฆฌ์ ์ธ๋ฐ๋ ๋ถ๊ตฌํ๊ณ ํ๊ตญ ์๊ฐ๋๊ฐ ์๋ UTC๋ก ์ค์ ๋์ด์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ๋๋ 2022-03-19 12:00
๊ณผ ๊ฐ์ ๋ฌธ์์ด ํํ๊ฐ ์๋ Unix Timestamp์ ๋ฐ๋ฆฌ์ด๊ฐ ๋ถ์ฌ๋ ์ํ๋ก ์๋ฒ์ ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ๊ณผ ์๋ต์ ์ฌ์ฉ๋ฉ๋๋ค. ๊ฐ๋์ฉ ๊ตญ๋ด ์๊ฐ๋ง ๋ค๋ฃจ๋ ๊ฐ๋ฐ์๋ค์ด UTC ๋๋ Unix Timestamp์ ๋ํด์ ๋ชจ๋ฅด๋ ๊ฒฝ์ฐ๋ ๊ฝค ๋ง์์ต๋๋ค. ๋ฐ๋ฆฌ์ด ํ์์ Unix Timestamp๋ฅผ ์ ๋ฌ๋ฐ์์ผ๋ ์ค์ ๋ก ๋ณํํด๋ณด๋ 9์๊ฐ์ด ๋น ์ง๊ฒ ์๋๋ผ ์คํ๋ ค 9์๊ฐ์ด ๋ํด์ง ์ํ๋ก ์ ๋ฌํ๋ ๊ฒฝํ๋ ์์ต๋๋ค.
Java Date Format
์๋ฒ์ ํด๋ผ์ด์ธํธ ๊ฐ์ ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ฑฐ๋ ๊ฐ๋ฐ์ ์ฌ์ด์ API๋ฅผ ์ ๊ณตํ ๋์๋ ์์ ์ด์ผ๊ธฐํ Unix Timestamp๋ก ์ ๋ฌํ๋๋ก ์คํ์ ๋ง์ถ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ฐ๋ฐ์๊ฐ ์๋ ์ผ๋ฐ ์ฌ์ฉ์๊ฐ ์๋น์ค ๋ด์์ CSV ๋๋ ์์
ํ์ผ ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์
๋ก๋ํ๊ฑฐ๋ ๋ค์ด๋ก๋ ๋ฐ์๋์๋ ์ซ์๊ฐ์ธ Unix Timestamp๊ฐ ์๋ 2022-03-19 12:00:00
๊ณผ ๊ฐ์ ์ด๋ ํ ๋ฌธ์ ํํ์ด์ด์ผํฉ๋๋ค. ์๋ํ๋ฉด ์ผ๋ฐ์ธ๋ค์ UTC๊ฐ ๋ฌด์์ธ์ง Unix Timestamp๊ฐ ๋ฌด์์ธ์ง ๋ชจ๋ฅด๋ ์ฌ๋์ด ๋ง์ผ๋๊น์. ์ฌ์ง์ด๋ ๊ฐ๋ฐ์๋ค ์ค์์๋โฆ
์๋ฐ 8์ Date/Time API์ ๋ํด์๋ ๋ค์ด๋ฒ D2์ ๊ณต์ ๋ Java์ ๋ ์ง์ ์๊ฐ API๋ฅผ ์ฐธ๊ณ ํ์๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
DateTimeFormatter
์๋ฐ 8์ ๋ ์ง ๋ฐ ์๊ฐ ํด๋์ค์ ๋ํด์ ๋ ์ง ํฌ๋งท์ ์ ์ฉํด์ผํ๋ ๊ฒฝ์ฐ DateTimeFormatter๋ฅผ ์ฌ์ฉํด์ผํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ผ๋ฐ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ก ๋ ์ง ๋ฐ์ดํฐ๋ฅผ ๋ณํํ ์ ์์ฃ .
TimeZone tzSeoul = TimeZone.getTimeZone("Asia/Seoul");
String dateStr = "2022-03-19 12:00:00";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(tzSeoul.toZoneId());
ZonedDateTime dateTime = ZonedDateTime.parse(dateStr, dateTimeFormatter);
System.out.printf("%s -> %s%n", dateStr, dateTime);
์ ์ฝ๋๋ ์ดํดํ๊ธฐ์๋ ์ฌ์ฐ๋ ํ๊ฐ์ง ๋ฌธ์ ์ ์ ์ด๋ค ํน์ ํ ํํ์ ๋ฌธ์์ด๋ก ๊ตฌ์ฑ๋ ๋ฐ์ดํฐ๋ง ๋ณํํ ์ ์๋ค๋ ์ ์ ๋๋ค.
๋ง์ฝ, ์๋น์ค ์ฌ์ฉ์๊ฐ 2022๋ 3์ 19์ผ 0์์ ์๊ฐ์ ํํํ๊ณ ์ ํ๋ค๋ฉด 2022-03-19 00:00:00๊ณผ ๊ฐ์ด ๋ถํ์ํ๊ฒ 00:00:00์ ๋ถ์ฌ์ผํ๋ ๋จ์ ์ด ์๊ธฐ๊ฒ ๋ฉ๋๋ค. ์ด๋ฅผ ๋ณด์ํ๊ธฐ ์ํด์๋ ์ฌ๋ฌ๊ฐ์ง ํ์์ ๋ ์ง ํฌ๋งท์ ์ฒ๋ฆฌํ ์ ์๋ ์ฝ๋๊ฐ ํ์ํฉ๋๋ค.
DateTimeFormatterBuilder
์ฌ๋ฌ๊ฐ์ง ํํ์ ๋ ์ง ํ์์ ์ง์ํด์ผํ๋ ๊ฒฝ์ฐ์๋ Optional ํจํด์ ์ ์ฉํด์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค. DateTimeFormatter์ ๊ทธ๋๋ก ์ ์ฉํ ์๋ ์์ผ๋ DateTimeFormatterBuilder๋ฅผ ํตํด ์ฌ๋ฌ๊ฐ์ง ์ฒ๋ฆฌ ๋ฐฉ์์ ๋ํ ์ต์ ์ด ์ ์ฉ๋ ํํ๋ก DateTimeFormatter๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
TimeZone tzSeoul = TimeZone.getTimeZone("Asia/Seoul");
DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()
.appendPattern("[yyyy-MM-dd HH:mm:ss]")
.appendPattern("[yyyy-MM-dd HH:mm]")
.appendPattern("[yyyy-MM-dd]")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter()
.withZone(tzSeoul.toZoneId());
String[] dateStrArr = new String[]{"2022-03-19 00:00:00", "2022-03-19 00:00", "2022-03-19"};
for (String dateStr : dateStrArr) {
ZonedDateTime dateTime = ZonedDateTime.parse(dateStr, dateTimeFormatter);
System.out.printf("%s -> %s%n", dateStr, dateTime);
}
// 2022-03-19 00:00:00 -> 2022-03-19T00:00+09:00[Asia/Seoul]
// 2022-03-19 00:00 -> 2022-03-19T00:00+09:00[Asia/Seoul]
// 2022-03-19 -> 2022-03-19T00:00+09:00[Asia/Seoul]
Unable to obtain LocalTime from TemporalAccessor
TimeZone tzSeoul = TimeZone.getTimeZone("Asia/Seoul");
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd HH:mm:ss][yyyy-MM-dd HH:mm][yyyy-MM-dd]").withZone(tzSeoul.toZoneId());
String[] dateStrArr = new String[]{"2022-03-19 00:00:00", "2022-03-19 00:00", "2022-03-19"};
for (String dateStr : dateStrArr) {
ZonedDateTime dateTime = ZonedDateTime.parse(dateStr, dateTimeFormatter);
System.out.printf("%s -> %s%n", dateStr, dateTime);
}
์์ ๊ฐ์ด DateTimeFormatterBuilder๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์๋ DateTimeFormatter ํจํด ์์ฒด๋ก ๋ ์ง ํฌ๋งท ์ฒด์ด๋์ ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋, 2022-03-19์ ๊ฐ์ด ์๊ฐ ๋ถ๋ถ์ด ์๋ ํํ์ ๊ฒฝ์ฐ์๋ ๋ค์๊ณผ ๊ฐ์ด ์ฒ๋ฆฌํ ์ ์๋ค๋ ์์ธ๊ฐ ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค.
java.time.format.DateTimeParseException: Text '2022-03-19' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO,Asia/Seoul resolved to 2022-03-19 of type java.time.format.Parsed
at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:598)
at test.Main.main(Main.java:17)
Caused by: java.time.DateTimeException: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO,Asia/Seoul resolved to 2022-03-19 of type java.time.format.Parsed
at java.base/java.time.ZonedDateTime.from(ZonedDateTime.java:566)
Caused by: java.time.DateTimeException: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO,Asia/Seoul resolved to 2022-03-19 of type java.time.format.Parsed
at java.base/java.time.format.Parsed.query(Parsed.java:235)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
... 2 more
Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {},ISO,Asia/Seoul resolved to 2022-03-19 of type java.time.format.Parsed
Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {},ISO,Asia/Seoul resolved to 2022-03-19 of type java.time.format.Parsed
at java.base/java.time.LocalTime.from(LocalTime.java:431)
at java.base/java.time.ZonedDateTime.from(ZonedDateTime.java:561)
... 4 more
๋ฐ๋ผ์, DateTimeFormatterBuilder๋ก ๋ฌธ์์ด๋ก ๊ตฌ์ฑ๋ ๋ ์ง ๋ฐ ์๊ฐ ๋ฐ์ดํฐ์ ๊ตฌ์ฑ๋์ง ์๋ ๋ถ๋ถ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊ฒ์ธ๊ฐ์ ๋ํ ์ต์ ์ ์ ์ฉํ์ฌ DateTimeFormatter๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉํ๋๊ฒ ์ข์๋ณด์ ๋๋ค.
๋ง์ฝ, ์ด ๊ธ์ ๋ณด์๋ ์ฌ๋ฌ๋ถ๋ค์ด ์ฌ๋ฌ๊ฐ์ง ํํ์ ๋ ์ง ํฌ๋งท์ ์ฒ๋ฆฌํ๊ธฐ ์ํด์ ์๋์ ๊ฐ์ด DateTimeFormattter๋ฅผ ์ฌ๋ฌ๊ฐ ๋ง๋ค์ด์ ์ฒ๋ฆฌํ๋ ์ฝ๋๋ฅผ ์์ฑํ๋ค๋ฉด DateTimeFormatterBuilder๋ก ํ๋์ DateTimeFormatter๋ฅผ ์ฌ์ฉํด์ ์ข ๋ ๊น๋ํ ํํ์ ์ฝ๋๋ก ๋ง๋ค์ด๋ณด์๊ธฐ๋ฅผ ์ถ์ฒํด๋๋ฆฝ๋๋ค.
String dateStr = "2022-03-19";
ZonedDateTime dateTime = null;
try {
dateTime = ZonedDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(tzSeoul.toZoneId()));
} catch (DateTimeException e) {
LocalDateTime localDateTime = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(tzSeoul.toZoneId())).atStartOfDay();
dateTime = ZonedDateTime.of(localDateTime, tzSeoul.toZoneId());
}
System.out.println(dateTime);
๊ฐ์ฌํฉ๋๋ค.