자바8의 java.time 패키지(LocalDate, LocalTime, LocalDateTime 등)

예전에 JPA와 LocalDate, LocalDateTime 사용하기 에서 자바8에서 추가된 새로운 날짜와 시간에 대한 API에 대해서 간단하게 글을 썼었다. 이번에는 자바8에 추가된 날짜와 시간 API에 대해서 조금 더 자세하게 알아보려고 한다. 해당 API는 java.time 패키지에 존재한다.

1. 날짜와 시간 객체 생성하기

1.1. LocalDate

로컬 날짜 클래스로 날짜 정보만 필요할 때 사용하면 된다.

LocalDate currentDate = LocalDate.now();    // 컴퓨터의 현재 날짜 정보를 저장한 LocalDate 객체를 리턴한다. 결과 : 2016-04-01 
LocalDate targetDate = LocalDate.of(int year, int month, int dayOfMonth);   // 파라미터로 주어진 날짜 정보를 저장한 LocalDate 객체를 리턴한다. 결과 : 1986-11-22
리턴 타입 메소드(매개변수) 설명
int getYear()
Month getMonth() Month 열거 값(JANUARY, FEBRUARY, MARCH ..)
int getMonthValue() 월(1, 2, 3 ..)
int getDayOfYear() 일년의 몇 번째 일
int getDayOfMonth() 월의 몇 번째 일
DayOfWeek getDayOfWeek() 요일(MONDAY, TUESDAY, WEDNESDAY..)
boolean isLeapYear() 윤년여부

1.2. LocalTime

로컬 시간 클래스로 시간 정보만 필요할 때 사용하면 된다.

LocalTime currentTime = LocalTime.now();    // 컴퓨터의 현재 시간 정보. 결과 : 16:24:02.408 
LocalTime targetTime = LocalTime.of(int hour, int minute, int second, int nanoOfSecond); // 파라미터로 주어진 시간 정보를 저장한 LocalTime 객체를 리턴한다. 
리턴 타입 메소드(매개변수) 설명
int getHour() 시간
int getMinute()
int getSecond()
int getNano() 나노초

1.3. LocalDateTime

날짜와 시간 정보 모두가 필요할 때 사용하면 된다.

LocalDateTime currentDateTime = LocalDateTime.now();    // 컴퓨터의 현재 날짜와 시간 정보. 결과 : 2016-04-01T16:34:24.757
LocalDateTime targetDateTime = LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond);

1.4. ZonedDateTime

ISO-8601 달력 시스템에서 정의하고 있는 타임존의 날짜와 시간을 저장하는 클래스이다. 결과는 2016-04-01T16:54:05.739+09:00[Asia/Seoul]와 같고, 맨 뒤에 +09:00[Asia/Seoul] 협정세계시와의 시차(+9시간)와 ZoneId(Asia/Seoul) 정보가 붙는다.

ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC"));
ZonedDateTime seoulDateTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
리턴 타입 메소드(매개변수) 설명
ZoneId getZone() ZoneId를 리턴(Asia/Seoul)
ZoneOffset getOffset() UTC와의 시차를 리턴(+09:00)

2. 날짜와 시간 조작하기

2.1. 날짜와 시간을 더하기거나 빼는 메소드

LocalDate, LocalDateTime, ZonedDateTime 클래스는 각각 년, 월, 일, 주를 더하거나 뺄 수 있다.

LocalDateTime currentDateTime = LocalDateTime.now();
LocalDateTime targetDateTime = currentDateTime
        .plusYears(long)       // 년도 더하기
        .minusYears(long)      // 년도 빼기
        .plusMonths(long)      // 월 더하기 
        .minusMonths(long)     // 월 빼기
        .plusDays(long)        // 일 더하기 
        .minusDays(long)       // 일 빼기
        .plusWeeks(long)       // 주 더하기
        .minusWeeks(long);     // 주 빼기

LocalTime, LocalDateTime, ZonedDateTime 클래스는 각각 시간, 분, 초, 나노초를 더하거나 뺄 수 있다.

LocalDateTime targetDateTime2 = currentDateTime
        .plusHours(long)       // 시간 더하기
        .minusHours(long)      // 시간 빼기
        .plusMinutes(long)     // 분 더하기 
        .minusMinutes(long)    // 분 빼기
        .plusSeconds(long)     // 초 더하기 
        .minusSeconds(long)    // 초 빼기
        .plusNanos(long)       // 나노초 더하기
        .minusNanos(long);     // 나노초 빼기

2.2. 날짜와 시간을 변경하는 메소드

LocalDate, LocalDateTime, ZonedDateTime 클래스는 각각 년, 월, 월의 몇 번째 일인지, 년의 몇번 번째 일인지를 변경할 수 있다.

LocalDateTime targetDateTime3 = currentDateTime
                .withYear(int)          // 년도를 변경
                .withMonth(int)         // 월 변경
                .withDayOfMonth(int)    // 월의 일을 변경
                .withDayOfYear(int);    // 년도의 일을 변경
                .with(TemporalAdjuster adjuster) // 현재 날짜를 기준으로 상대적인 날짜로 변경

마지막에 .with(TemporalAdjuster adjuster) 메소드를 사용하면 현재 날짜를 기준으로 년도의 첫 번째 일, 마지막 일, 월의 첫 번째 일, 마지막일, 지난 요일 및, 돌아오는 요일 등 상대적인 날짜로 변경을 할 수 있다.

LocalDateTime targetDateTime4 = currentDateTime
        .with(TemporalAdjusters.firstDayOfYear())       // 이번 년도의 첫 번째 일(1월 1일)
        .with(TemporalAdjusters.lastDayOfYear())        // 이번 년도의 마지막 일(12월 31일)
        .with(TemporalAdjusters.firstDayOfNextYear())   // 다음 년도의 첫 번째 일(1월 1일)
        .with(TemporalAdjusters.firstDayOfMonth())      // 이번 달의 첫 번째 일(1일)
        .with(TemporalAdjusters.lastDayOfMonth())       // 이번 달의 마지막 일
        .with(TemporalAdjusters.firstDayOfNextMonth())  // 다음 달의 첫 번째 일(1일)
        .with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)) // 이번 달의 첫 번째 요일(여기서는 월요일)
        .with(TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY))  // 이번 달의 마지막 요일(여기서는 마지막 금요일)
        .with(TemporalAdjusters.next(DayOfWeek.FRIDAY))       // 다음주 금요일
        .with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY)) // 다음주 금요일(오늘 포함. 오늘이 금요일이라면 오늘 날짜가 표시 된다.)
        .with(TemporalAdjusters.previous(DayOfWeek.FRIDAY))     // 지난주 금요일
        .with(TemporalAdjusters.previousOrSame(DayOfWeek.FRIDAY));// 지난주 금요일(오늘 포함)

LocalTime, LocalDateTime, ZonedDateTime 클래스는 각각 시간, 분, 초, 나노초를 변경할 수 있다.

LocalDateTime targetDateTime5 = currentDateTime
        .withHour(int)      // 시간 변경
        .withMinute(int)    // 분 변경
        .withSecond(int)    // 초 변경
        .withNano(int);     // 나노초 변경

3. 날짜와 시간을 비교하는 메소드

3.1. 날짜 비교하기

LocalDate, LocalDateTime은 아래와 같이 isBefore(ChronoLocalDate other), isEqual(ChronoLocalDate other), isAfter(ChronoLocalDate other) 메소드를 사용해 날짜를 비교할 수 있다. 리턴 타입은 boolean이다.

LocalDateTime startDateTime = LocalDateTime.now();  // 2016-04-01T23:39:57.008
LocalDateTime endDateTime = LocalDateTime.of(2016, 4, 1, 23, 59, 59);

// startDateTime이 endDateTime 보다 이전 날짜 인지 비교
startDateTime.isBefore(endDateTime);    // true

// 동일 날짜인지 비교
startDateTime.isEqual(endDateTime); // false

// startDateTime이 endDateTime 보다 이후 날짜인지 비교
startDateTime.isAfter(endDateTime); // false

3.2. 시간 비교하기

LocalTime과 LocalDateTime은 isBefore(LocalTime other), isAfter(LocalTime other) 메소드를 사용해 시간을 비교할 수 있다. 리턴 타입은 boolean이다.

LocalTime startTime = LocalTime.now();  // 23:52:35.603
LocalTime endTime = LocalTime.of(23, 59, 59);

// startTime이 endTime 보다 이전 시간 인지 비교
startTime.isBefore(endTime);    // true

// startTime이 endTime 보다 이후 시간 인지 비교
startTime.isAfter(endTime); // false

3.3. 날짜 차이 계산하기

LocalDate는 until(ChronoLocalDate endDate) 메소드를 사용해서 날짜 차이를 계산할 수 있으며, 리턴 타입은 java.time.Period 이다. Period 클래스의 getYears(), getMonths(), getDays() 메소드를 사용해서 년도 차이, 월의 차이, 일의 차이를 계산 할 수 있다.

LocalDate currentDate = LocalDate.now(); // 2016-04-02
LocalDate targetDate = LocalDate.of(2016,5,5);

Period period = currentDate.until(targetDate);

period.getYears();      // 0년
period.getMonths();     // 1개월
period.getDays();       // 3일 차이

또한 Period 클래스의 between(LocalDate startDate, LocalDate endDate) 메소드를 사용해서도 날짜 차이를 구할 수 있고, 리턴 타입은 Period 이다.

LocalDate startDate = LocalDate.now(); // 2016-04-02
LocalDate endDate = LocalDate.of(2016,5,5);

Period period = Period.between(startDate, endDate);

period.getYears();      // 0년
period.getMonths();     // 1개월
period.getDays();       // 3일 차이

3.4. 시간 차이 계산하기

LocalDate, LocalTime, LocaDateTime은 until(Temporal end, TemporalUnit unit) 메소드를 사용하여 시간 차이를 계산 할 수 있고, 리턴 타입은 long 이다. 두 번째 파라미터인 TemporalUnit 인터페이스의 구현체로 자바가 제공해주는 ChronoUnit을 사용하면 된다.

LocalTime startTime = LocalTime.now();  // 00:35:39
LocalTime endTime = LocalTime.of(12,59,00);

startTime.until(endTime, ChronoUnit.HOURS); 

또 다른 방법으로 java.time.Duration 클래스의 between(Temporal start, Temporal end) 메소드를 사용해서도 시간 차이를 구할 수 있다. 리턴 타입은 Duration 이다.

LocalTime startTime = LocalTime.now();  // 00:35:39
LocalTime endTime = LocalTime.of(12,59,00);

Duration duration = Duration.between(startTime, endTime);
duration.getSeconds();      // 초의 차이
duration.getNano();         // 나노초의 차이

3.5. 전체 시간을 기준으로 차이 계산하기

3.3. 날짜 차이 계산하기에서 Period 클래스의 between()메소드를 사용해서 계산하는 경우, getDays()의 결과는 3 이었다. 하지만 실제 1개월 3일 차이이므로 33일이 나오도록 전체 일을 구하는 방법은 ChronoUnit 클래스의 between(Temporal start, Temporal end) 메소드를 사용하면 되고, 리턴 타입은 long 이다.

클래스 설명
ChronoUnit.YEARS 전체 년 차이
ChronoUnit.MONTHS 전체 월 차이
ChronoUnit.WEEKS 전체 주 차이
ChronoUnit.DAYS 전체 일 차이
ChronoUnit.HOURS 전체 시간 차이
ChronoUnit.SECONDS 전체 초 차이
ChronoUnit.MILLIS 전체 밀리초 차이
ChronoUnit.NANOS 전체 나노초 차이
LocalDate startDate = LocalDate.now(); // 2016-04-02
LocalDate endDate = LocalDate.of(2016,5,5);

ChronoUnit.DAYS.between(startDate, endDate); // 결과 : 33 (1개월 3일)

4. 날짜 포맷팅

LocalDate, LocalTime, LocaDateTime, ZonedDateTime 클래스의 format(DateTimeFormatter formatter) 메소드를 사용해서 원하는 문자열로 변환시킬 수 있다.

LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 M월 d일 a h시 m분");
String nowString = now.format(dateTimeFormatter);   // 결과 : 2016년 4월 2일 오전 1시 4분

ofPattern() 메소드의 파라미터로 사용할 수 있는 패턴 기호에 대한 설명은 자바 API DateTimeFormatter 클래스의 Pattern for Formatting and Parsing을 참고하면 된다. image1

출처(참고) : 한빛미디어 이것이 자바다(저자 신용권)