본문 바로가기
Dev Log/Java

Modern Java In Action 정리 - 12 새로운 날짜와 시간 API

by 삽질하는큐 2020. 7. 4.

Date, Calendar

java 1.0에서는 날짜를 표기하기 위해서 Date 클래스를 만들었다.

 

java.util.Date는 문제가 많다. 

  • 특정 시점을 날짜가 아닌 밀리초 단위로 표현한다.
  • 기준이 1900년이다.
  • 1일은 1로 표기하고 1월은 0으로 표기한다.
  • mutable하다
Date date = new Date(117, 8, 21);

를 출력하면 Thu Sep 21 00:00:00 CET 2017 라고 나오는데

2017년이 117로 써야 하고 9월인데 8로 써야 하고

CET (중앙유럽시간대)를 쓰니까 뭐 이거 불편한게 이만저만이 아니다.

 

그래서 java 1.1에서 java.util.Calendar를 만들었다.

이것도 문제가 많다.

  • 여전히 달은 0부터 시작했다
  • mutable하다

 

LocalDate

java 8에서 Joda-Time이라는 third party library에 있던 기능을 많이 추가했다. LocalDate는 시간을 제외한 날짜 yyyy-mm-dd 를 표현한다.

LocalDate localDate = LocalDate.of(2020, 7, 4);
int year = localDate.getYear();           // 2020
Month month = localDate.getMonth();       // JULY
int day = localDate.getDayOfMonth();      // 4
DayOfWeek dow = localDate.getDayOfWeek(); // SATURDAY
int len = localDate.lengthOfMonth();      // 31 (7월의 일 수)
boolean leap = localDate.isLeapYear();    // false 윤년 여부

 

 

ChronoField라는 enum을 써서도 값을 가져올 수 있다.

int yearChronoField = localDate.get(ChronoField.YEAR);
int monthChronoField = localDate.get(ChronoField.MONTH_OF_YEAR);
int dayChronoField = localDate.get(ChronoField.DAY_OF_MONTH);

chronofield는 위와 같이 정의되어 있다.

하지만 뭐 getYear() 같은 함수들이 있는데 쓸일 있을까 싶다.

 

 

LocalTime

시분초를 나타낼 때는 LocalTime을 쓸 수 있다.

LocalTime time = LocalTime.of(13, 45, 20); // 13:45:20
int hour = time.getHour();     // 13
int minute = time.getMinute(); // 45
int second = time.getSecond(); // 20

 

String을 파싱하는 방법으로도 인스턴스를 만들 수 있다.

LocalDate date = LocalDate.parse("2020-07-04");
LocalTime time = LocalTime.parse("13:45:20");

 

 

LocalDateTime

날짜와 시간을 모두 포함할 때 쓰는 클래스이다. 실질적으로 Date는 LocalDateTime으로 대체된다고 생각하면 될 것 같다. LocalDateTime 내부에 LocalDate와 LocalTime이 필드로 정의되어 있다.

LocalDateTime dt1 = LocalDateTime.of(2020, Month.JULY, 4, 21, 13, 45, 20);
LocalDateTime dt2 = LocalDateTime.of(localDate, localTime);
LocalDateTime dt3 = localDate.atTime(13, 45, 20);
LocalDateTime dt4 = localDate.atTime(localTime);
LocalDateTime dt5 = localTime.atDate(localDate);

 

LocalDateTime에서 LocalDate나 LocalTime만 따로 추출할 수도 있다.

LocalDate date1 = dt1.toLocalDate();
LocalTime time1 = dt1.toLocalTime();

 

 

Duration, Period

지속시간과 시간 간격을 Duration과 Period로 나타낼 수 있다.

Duration threeMinutes = Duration.ofMinutes(3);
Duration threeMins = Duration.of(3, ChronoUnit.MINUTES);

Period tenDays = Period.ofDays(10);
Period threeWeeks = Period.ofWeeks(3);
Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);

 

 

날짜 조정하기

java.time API 들은 immutable하기 때문에 변경처럼 보이지만 실제로는 새로운 객체를 만드는 것이다.

날짜를 특정 값으로 설정하기

LocalDate date1 = LocalDate.of(2020, 7, 4); // 2020-07-04
LocalDate date2 = date1.withYear(2011); // 2011-07-04
LocalDate date3 = date2.withDayOfMonth(25); // 2011-07-25
LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 2); // 2011-02-25

 

날짜를 상대 값으로 바꾸기

LocalDate date1 = LocalDate.of(2020, 7, 4); // 2020-07-04
LocalDate date2 = date1.plusWeeks(1); // 2020-07-11
LocalDate date3 = date2.minusYears(6); // 2014-07-11
LocalDate date4 = date3.plus(6, ChronoUnit.MONTHS); // 2015-01-11

 

Formatting

포매팅과 관련된 패키지가 새로 추가되었다. java.time.format이며 DateTimeFormatter 에서는 여러 포맷의 상수를 미리 정의하고 있다.

LocalDate date = LocalDate.of(2014, 3, 18);
String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE); // 20140318
String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE); // 2014-03-18

 

custom format은 다음과 같이 하게 되면 된다.

 

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate date1 = LocalDate.of(2014, 3, 18);
String formattedDate = date1.format(formatter);
LocalDate date2 = LocalDate.parse(formattedDate, formatter);
System.out.println(formattedDate);

 

DateTimeFormatter는 기존의 java.util.DateFormat 클래스와 달리 모든 스레드에서 안전하다.

 

 

시간대 사용하기

글로벌 서비스를 만들게 된다면 사용할거라고 보는데 timezone을 고려한 DateTime이라고 보면 된다.

ZonedDateTime은 LocalDateTime과 ZoneId를 포함한 개념의 클래스이다.

ZoneId romeZone = ZoneId.of("Europe/Rome");
LocalDate date = LocalDate.of(2014, Month.MARCH, 18);
ZonedDateTime zdt1 = date.atStartOfDay(romeZone);
LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);
ZonedDateTime zdt2 = dateTime.atZone(romeZone);
Instant instant = Instant.now();
ZonedDateTime zdt3 = instant.atZone(romeZone);