Java 날짜 - Date-Time API

LocalDateTime/OffsetDateTime/ZonedDateTime

개요

JavaSE 8부터는 날짜/시간을 다루는 새로운 API로 Date and Time API가 도입되었다. Date-Time API는 java.time 패키지에 포함되어 있다.
java.time 패키지로 제공되는 주요 클래스는 아래와 같다.

  • LocalDateTime/LocalDate/LocalTime: 시차 정보가 없는 로컬 일시
  • OffsetDateTime/OffsetTime: 시차 정보가 있는 날짜와 시간
  • ZonedDateTime: 타임존와 지역을 기반으로 한 정보(서머 타임 등)가 있는 날짜와 시간

일반적으로는 시차 정보를 필요로 하지 않는 경우에는 Local~클래스를 사용하고, 그렇지 않으면 Zoned~클래스를 하는 식으로 구분된다. 그리고 Offset~클래스를 이용하는 것은 별로 없을까 생각된다.

LocalDateTimenow/of/parse 메서드

now/of/parse 메서드는 문자열에서 날짜/시간 값을 생성한다.

public static LocalDateTime now()
public static LocalDateTime of(int year, int month, int day, int hour, int minute [,int second [,int nano]])
public static LocalDate parse(CharSequence text)
    year: 
    month: 
    day: 
    hour: 
    minute:
    second:
    nano: 나노초
    text: 날짜 시간 문자열

java.time 패키지에서는 목적에 따라 Local/Offset/Zoned 계열 클래스가 준비되어 있는데, 이 메소드들은 생성하는 방법은 동일하다.
먼저 현재 시간을 표시하려면 now 메서드를 사용한다.
of 메서드는 연월일/시분초를 지정하여 객체를 생성한다. parse 메소드를 사용하여 일자 시각 캐릭터 라인으로부터 객체를 생성할 수도 있다.

package com.devkuma.basic.datetime;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class TimeCreate {
    public static void main(String[] args) {
        LocalDateTime local = LocalDateTime.now();
        System.out.println(local);
        // 결과: 2022-09-05T12:03:34.123041

        OffsetDateTime offset = OffsetDateTime.of(
                2022, 9, 5, 12, 3, 29, 0, ZoneOffset.of("+09:00"));
        System.out.println(offset);
        // 결과: 2022-09-05T12:03:29+09:00

        ZonedDateTime zoned = ZonedDateTime.parse("2022-09-05T12:03:29+09:00[Asia/Seoul]");
        System.out.println(zoned);
        // 결과: 2022-09-05T12:03:29+09:00[Asia/Seoul]
    }
}

실행 결과:

false
false
true

각 객체에서 다음 메서드를 사용하여, 각각의 날짜/시간 요소에 액세스할 수도 있다.

각각의 날짜/시간 요소에 액세스하는 메소드

메소드 개요
getYear
getMonth 월(Month 타입)
getMonthValue 월(1~12)
getDayOfMonth
getDayOfWeek 요일
getDayOfYear 연간 통산일
getHour 시간
getMinute
getSecond
getNano 나노초

between 메서드

between 메서드는 날짜/시간 값의 차이 구한다.

public static Period between(LocalDate start, LocalDate end) // Period
public static Duration between(Temporal start, Temporal end) // Duration
    start: 시작일시
    end: 종료일시

Period/Duration#between 메서드를 사용하여, 일자 시각 객체간의 시간차를 구할 수가 있다. Period는 날짜 간격을 나타내고, Duration은 시간 간격을 나타내는 객체이다

  • Temporal 클래스는 Local/Offset/Zonedr 계열 클래스 모든 인터페이스이다.

다음은 미리 준비한 2개의 날짜/시간의 차이를 Period/Duration#between 메서드로 구하는 예제이다.

TimeBetween.java

package com.devkuma.basic.datetime;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Period;

public class TimeBetween {
    public static void main(String[] args) {
        LocalDateTime local1 = LocalDateTime.of(
                2021, 1, 1, 3, 30, 0, 0);
        LocalDateTime local2 = LocalDateTime.of(
                2022, 9, 5, 12, 14, 30, 0);
        System.out.println(local1); // 결과: 2021-01-01T03:30
        System.out.println(local2); // 결과: 2022-09-05T12:14:30

        Period period = Period.between(local1.toLocalDate(), local2.toLocalDate());
        System.out.println("날짜 차이: " + period);   // 결과: 날짜 차이: P1Y8M4D

        System.out.println("날짜 차이: " +
                period.getYears() + "년 " + period.getMonths() + "월 " +
                period.getDays() + "일"); // 결과: 날짜 차이: 1년 8월 4일

        Duration duration = Duration.between(local1, local2);
        System.out.println("시간 차이: " + duration);
        // 결과: 시간 차이: PT14696H44M30S

        System.out.println("시간 차이: " + duration.toHours() + "시간");
        // 결과: 시간 차이: 14696시간

        System.out.println("시간 차이: " + duration.toMinutes() + "분");
        // 결과: 시간 차이: 881804분

        System.out.println("시간 차이: " + duration.getSeconds() + "초");
        // 결과: 시간 차이: 52908270초
    }
}

실행 결과:

2021-01-01T03:30
2022-09-05T12:14:30
날짜 차이: P1Y8M4D
날짜 차이: 1년 8월 4일
시간 차이: PT14696H44M30S
시간 차이: 14696시간
시간 차이: 881804분
시간 차이: 52908270초

Period/Duration 객체로 부터 일 수나 시간 수를 구하려면, 다음과 같은 메서드를 이용한다.

Period/Duration 클래스의 주요 메서드

클래스 메서드 개요
Period getYears 년수
getMonths 월수
getMonths 월수
Duration toDays 일수
toHours 시간 수
toMinutes 분수
toMillis 밀리초 수
toNanos 나노초 수

날짜 및 시간 데이터 계산

public LocalDateTime plus(long value, TemporalUnit unit)
public LocalDateTime minus(long value, TemporalUnit unit)
    value: 증감분
    unit: 단위

plus/minus 메서드를 사용하여, 일자 시각 요소를 더하고 뺄수 있다. 인수 unitTemporalUnit 인터페이스의 구현 클래스인 ChronoUnit의 상수로 추가 혹은 빼려는 단위를 지정한다.

TemporalUnit 인터페이스의 주요 상수

상수 개요
YEARS
MONTHS
DAYS
WEEKS
HOURS 시간
MINUTES
SECONDS
MILLIS 밀리
NANOS 나노초

다음은 미리 준비한 날짜에 대해, 3개월 후 10일 전의 날짜를 구하는 예제이다.

package com.devkuma.basic.datetime;

import java.time.LocalDateTime;

public class TimePlus {
    public static void main(String[] args) {
        LocalDateTime local = LocalDateTime.parse("2022-09-05T12:30");
        System.out.println(local);  // 결과: 2022-09-05T12:30
        System.out.println(local.plusMonths(3));    // 결과: 2022-12-05T12:30
        System.out.println(local.minusDays(10));    // 결과: 2022-08-26T12:30
    }
}

실행 결과:

2022-09-05T12:30
2022-12-05T12:30
2022-08-26T12:30

또한, plus/minus 메서드에는 각각의 일자/시각 요소에 특화된 메소드가 다음과 같이 있다.

날짜/시간을 가산/감산하는 방법

메서드 개요
plusYears/minusYears
plusMonths/minusMonths
plusDays/minusDays
plusWeeks/minusWeeks 주수
plusHours/minusHours 시간
plusMinutes/minusMinutes
plusSeconds/minusSeconds
plusNanos/minusNanos 나노초

Date/Calendar 클래스에서 DateTime-API 클래스로 상호 변환

public static Date from(Instant instant) // Date
public Instant toInstant() // Date/Calendar
public static LocalDateTime ofInstant(Instant instant, ZoneId zone) // XxxxxDateTime
    instant: 변환할 인스턴트

새롭게 Date-Time API가 도입되었다고 해도, 갑자기 모든 코드를 Date-Time API로 통일하는 것은 현실적으로 쉽지 않다. 당분간은, 기존에 java.util 패키지와 병행하게 될 것이다. 그래서 기존의 Date/Calendar 클래스에 Date-Time API와 상호 변환하기 위한 메소드를 제공하고 있다.
Date#from 메서드는 주어진 Instant 객체에서 Date 객체를 생성한다. Instant는 날짜 시간을 1970년 1월 1일 이후의 경과 시간으로 유지하는 클래스이다. Date-Time API의 날짜/시간 클래스는 각각 toInstant 메소드를 제공하고 있어서 Instant 객체를 생성할 수 있게 되어 있으므로, 이를 from 메소드에 건네주면 Date 객체를 생성할 수 있다.

  • Calendar 클래스에는 Date#from 메서드에 해당하는 메서드는 없다. 생성된 Date 객체로부터 Calendar 객체를 생성하게 된다.

Calendar/Date 클래스에도 toInstant 메소드는 제공하고 있다. 생성된 Instant 객체를 LocalDateTime/OffsetDateTime/ZonedDateTime 클래스의 ofInstant 메서드에 전달하여 각각 해당 객체를 생성할 수 있다.

다음은 LocalDateTime 객체를 Date 객체로, Calendar 객체를 LocalDateTime 객체로 변환하는 예제이다.

package com.devkuma.basic.datetime;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.Date;

public class TimeTrans {
    public static void main(String[] args) {
        LocalDateTime local = LocalDateTime.now();
        System.out.println(local);  // 결과: 2022-09-05T14:32:05.526238

        Instant instant = local.toInstant(ZoneOffset.of("+09:00"));
        Date date = Date.from(instant);
        System.out.println(date);   // 결과: Mon Sep 05 14:32:05 KST 2022

        Calendar cal = Calendar.getInstance();
        Instant instant2 = cal.toInstant();
        LocalDateTime local2 = LocalDateTime.ofInstant(instant2, ZoneId.of("Asia/Seoul"));
        System.out.println(local2); // 결과: 2022-09-05T14:32:05.542
    }
}

실행 결과:

2022-09-05T14:32:05.526238
Mon Sep 05 14:32:05 KST 2022
2022-09-05T14:32:05.542

String에서 LocalDate/LocalDateTime으로 변환하는 방법

Stringjava.time.LocalDate로 변환은 LocalDate.parseDateTimeFormatter를 이용하여 날짜 문자열을 변환한다.
Stringjava.time.LocalDateTime로 변환은 문자열을 LocalDate로 만들고, LocalTime와 같이 인자로 받아서 생성한다.

package com.devkuma.basic.datetime;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class StringConvent {
    public static void main(String[] args) {
        String strDate = "2022/12/12";
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");

        LocalDate localDate = LocalDate.parse(strDate, dateTimeFormatter);
        System.out.println(localDate);

        LocalDateTime ldt = LocalDateTime.of(localDate, LocalTime.of(0, 0));
        System.out.println(ldt);
    }
}

실행 결과:

2022-12-12
2022-12-12T00:00

날짜 문자열이 2022/12/12와 같은 형식이면, Format 지정은 DateTimeFormatter.ISO_DATE로 대체 할 수 있다. DateTimeFormatter.ISO_DATEyyyy-mm-dd를 상수로 선언한다.




최종 수정 : 2022-09-05