Java 날짜 - Date-Time API
개요
JavaSE 8부터는 날짜/시간을 다루는 새로운 API로 Date and Time API가 도입되었다. Date-Time API는 java.time 패키지에 포함되어 있다.
java.time 패키지로 제공되는 주요 클래스는 아래와 같다.
LocalDateTime/LocalDate/LocalTime: 시차 정보가 없는 로컬 일시OffsetDateTime/OffsetTime: 시차 정보가 있는 날짜와 시간ZonedDateTime: 타임존와 지역을 기반으로 한 정보(서머 타임 등)가 있는 날짜와 시간
일반적으로는 시차 정보를 필요로 하지 않는 경우에는 Local클래스를 사용하고, 그렇지 않으면 Zoned클래스를 하는 식으로 구분된다.
그리고 Offset~클래스를 이용하는 것은 별로 없을까 생각된다.
LocalDateTime의 now/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 메서드를 사용하여, 일자 시각 요소를 더하고 뺄수 있다. 인수 unit는 TemporalUnit 인터페이스의 구현 클래스인 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으로 변환하는 방법
String을 java.time.LocalDate로 변환은 LocalDate.parse와 DateTimeFormatter를 이용하여 날짜 문자열을 변환한다.
String을 java.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_DATE는 yyyy-mm-dd를 상수로 선언한다.