Java8 In Action 을 읽고 정리한 내용이다. 자바8에서 날짜와 시간 문제를 개선하는 새로운 날짜와 시간 API를 제공하는 새로운 기능에 대해서 설명한다.
Localdate, LocalTime, Instant, Duration, Period
java.time
패키지는 Localdate
, LocalTime
, LocalDateTime
, Instant
, Duration
, Period
등 새로운 클래스를 제공한다.
LocaDate와 LocalTime 사용
LocalDate
인스턴스는 시간을 제외한 날짜를 표현하는 불변 객체다. 정적 팩토리 메서드는 of
로 LocalDate
인스턴스를 만들 수 있다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31public class DateTimeExamples {
public static void main(String[] args) {
useLocalDate();
}
private static void useLocalDate() {
LocalDate today = LocalDate.now(); // 시스템의 현재 날짜 정보
System.out.println("today : " + today);
LocalDate date = LocalDate.of(2019, 06, 21);
System.out.println("date : " + date);
int year = date.getYear();
System.out.println("year : " + year);
Month month = date.getMonth();
System.out.println("month : " + month);
int day = date.getDayOfMonth();
System.out.println("day : " + day);
DayOfWeek dayOfWeek = date.getDayOfWeek();
System.out.println("dayOfWeek : " + dayOfWeek);
int len = date.lengthOfMonth(); // 6월의 일수
System.out.println("len : " + len);
boolean leap = date.isLeapYear(); // 윤년이 아님
System.out.println("leap : " + leap);
}
}
위에 코드에서 보여주는 것처럼
LocalDate
인스턴스는 년도, 달, 요일 등을 반환하는 메서드를 제공한다.
결과 화면1
2
3
4
5
6
7
8today : 2019-06-23
date : 2019-06-21
year : 2019
month : JUNE
day : 21
dayOfWeek : FRIDAY
len : 30
leap : false
get 메서드에 TemporalField를 이용해서 LocalDate값 읽기
1 | public class DateTimeExamples { |
결과 화면1
2
3
4date : 2019-06-21
year : 2019
month : 6
year : 2019
LocalTime 만들고 값 읽기
1 | public class DateTimeExamples { |
결과 화면1
2
3
4time : 13:45:20
hour : 13
minute : 45
second : 20
날짜와 시간 문자열로 LocalDate와 LocalTime의 인스턴스를 만드는 방법
1 | public class DateTimeExamples { |
결과 화면1
2date : 2019-06-20
time : 13:45:20
날짜와 시간 조합
LocalDateTime
은 LocalDate
와 LocalTime
을 쌍으로 갖는 복합 클래스다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public class LocalDatetimeExamples {
public static void main(String[] args) {
useLocalDateTime();
}
private static void useLocalDateTime() {
LocalDateTime dt1 = LocalDateTime.of(2019, Month.MARCH, 23, 20, 48, 11);
System.out.println("dt1 : " + dt1);
System.out.println("dt1.toLocalDate : " + dt1.toLocalDate());
System.out.println("dt1.toLocalTime : " + dt1.toLocalTime());
LocalDate date = LocalDate.of(2019, 06, 21);
LocalTime time = LocalTime.of(13, 45, 20);
LocalDateTime dt2 = LocalDateTime.of(date, time);
System.out.println("dt2 : " + dt2);
LocalDateTime dt3 = date.atTime(10, 30, 25);
System.out.println("dt3 : " + dt3);
LocalDateTime dt4 = date.atTime(time);
System.out.println("dt4 : " + dt4);
LocalDateTime dt5 = time.atDate(date);
System.out.println("dt5 : " + dt5);
}
}
결과 화면1
2
3
4
5
6
7dt1 : 2019-03-23T20:48:11
dt1.toLocalDate : 2019-03-23
dt1.toLocalTime : 20:48:11
dt2 : 2019-06-21T13:45:20
dt3 : 2019-06-21T10:30:25
dt4 : 2019-06-21T13:45:20
dt5 : 2019-06-21T13:45:20
Duration와 Period 정의
Duration
클래스의 정적 팩토리 메서드 between
으로 두 시간 객체 사이의 지속시간을 만들 수 있다. Period
클래스 팩토리 메서드 between
을 이용하면 두 LocalDate
의 차이를 확인할 수 있다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32public class DurationAndPeriodExamples
public static void main(String[] args) {
useDurationAndPeroid();
}
private static void useDurationAndPeroid() {
LocalTime time = LocalTime.of(13, 45, 20);
Instant instant = Instant.ofEpochSecond(44 * 365 * 86400);
Instant now = Instant.now();
Duration d1 = Duration.between(LocalTime.of(13, 45, 10), time);
Duration d2 = Duration.between(instant, now);
System.out.println("d1.getSeconds : " + d1.getSeconds());
System.out.println("d2.getSeconds : " + d2.getSeconds());
Duration threeMinutes = Duration.ofMinutes(3);
System.out.println("threeMinutes : " + threeMinutes);
Duration threeMinutes2 = Duration.of(3, ChronoUnit.MINUTES);
System.out.println("threeMinutes2 : " + threeMinutes2);
Period tendays = Period.ofDays(10);
System.out.println("tendays : " + tendays);
Period threeWeeks = Period.ofWeeks(3);
System.out.println("threeWeeks : " + threeWeeks);
Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);
System.out.println("twoYearsSixMonthsOneDay : " + twoYearsSixMonthsOneDay);
}
}
결과 화면1
2
3
4
5
6
7d1.getSeconds : 10
d2.getSeconds : 173709219
threeMinutes : PT3M
threeMinutes2 : PT3M
tendays : P10D
threeWeeks : P21D
twoYearsSixMonthsOneDay : P2Y6M1D
간격을 표현하는 날짜와 시간 클래스의 공통 메서드
메서드 | 정적 | 설명 |
---|---|---|
between | 네 | 두시간 사이의 간격을 생성함. |
from | 네 | 시간 단위로 간격을 생성함 |
of | 네 | 주어진 구성 요소에서 간격 인스턴스를 생성함. |
parse | 네 | 문자열을 파싱해서 간격 인스턴스를 생성함. |
addTo | 아니요 | 현재값의 복사본을 생성한 다음에 지정된 Temporal 객체에 추가함 |
get | 아니요 | 현재 간격 정보값을 읽음. |
isNegative | 아니요 | 간격이 음수인지 확인함 |
isZero | 아니요 | 간격이 0인지 확인함. |
minus | 아니요 | 현재값에서 주어진 시간을 뺀 복사본을 생성함. |
multipliedBy | 아니요 | 현재값에 주어진 값을 곱한 복사본을 생성함. |
negated | 아니요 | 주어진 값의 부호를 반전한 복사본을 생성함. |
plus | 아니요 | 현재값에 주어진 시간을 더한 복사본을 생성함. |
subtractFrom | 아니요 | 지정된 Temporal 객체에서 간격을 뺌. |
날짜 조정, 파싱, 포메팅
withAttribute
메서드로 기존의 LocalDate
를 바꾼 버전을 직접 간단하게 만들 수 있다.
절대적인 방식으로 LocalDate의 속성 바꾸기
1 | public class WithAttributeExamples { |
결과 화면1
2
3
4date1 : 2019-06-23
date2 : 2018-06-23
date3 : 2018-06-30
date4 : 2018-07-30
상대적인 방식으로 LocalDate의 속성 바꾸기
1 | public class WithAttributeExamples { |
결과 화면1
2
3
4date1 : 2019-06-23
date2 : 2019-06-30
date3 : 2019-06-09
date4 : 2019-12-09
특정 시점을 표현하는 날짜 시간 클래스의 공통 메서드
메서드 | 정적 | 설명 |
---|---|---|
from | 네 | 주어진 Temporal 객체를 이용해서 클래스의 인스턴스를 생성함. |
now | 네 | 시스템 시계로 Temporal 객체를 생성함. |
of | 네 | 주어진 구성 요소에서 Temporal 객체의 인스턴스를 생성함. |
parse | 네 | 문자열을 파싱해서 Temporal 객체를 생성함. |
atOffset | 아니요 | 시간대 오프셋과 Temporal 객체를 합침. |
atZone | 아니요 | 시간대와 Temporal 객체를 합침. |
foramt | 아니요 | 지정도니 포매터를 이용해서 temporal 객체를 문자열로 변환함(Instant는 지원하지 않음.) |
get | 아니요 | Temporal 객체의 상태를 읽음. |
minus | 아니요 | 특정 시간을 뺀 Temporal 객체의 복사본을 생성함. |
plus | 아니요 | 특정 시간을 더한 Temporal 객체의 복사본을 생성함. |
with | 아니요 | 일부 상태를 바꾼 Temporal 객체의 복사본을 생성함. |
TemporalAdjusters 사용하기
다음 주 일요일, 돌아오는 평일, 어떤 달의 마지막 날 등 좀 더 복잡한 날짜 조정 기능이 필요 할 때 이용1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class AdjusterExamples {
public static void main(String[] args) {
useTemporalAdjuster();
}
private static void useTemporalAdjuster() {
LocalDate date1 = LocalDate.of(2019, 06, 21);
System.out.println("date1 : " + date1);
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));
System.out.println("date2 : " + date2);
LocalDate date3 = date2.with(lastDayOfMonth());
System.out.println("date3 : " + date3);
}
}
결과 화면1
2
3date1 : 2019-06-21
date2 : 2019-06-23
date3 : 2019-06-30
TemporalAdjusters 클래스의 팩토리 메서드(API 레퍼런스 참조)
메서드 | 설명 |
---|---|
dayOfWeekInMonth | ‘3월의 둘째 화요일’처럼 서수 요일에 해당하는 날짜를 반환하는 TemporalAdjuster를 반환함. |
firstDayofMonth | 현재 달의 첫 번째 날짜를 반환하는 TemporalAdjuster를 반환함. |
firstDayOfNextMonth | 다음 달의 첫 번째 날짜를 반환하는 TemporalAdjuster를 반환함. |
firstDayOfNextYear | 내년의 첫 번째 날짜를 반환하는 TemporalAdjuster를 반환함. |
firstDayOfYear | 올해의 첫 번째 날짜를 반환하는 TemporalAdjuster를 반환함. |
firstInMonth | ‘3월의 첫 번째 화요일’처럼 현재 달의 첫 번째 요일에 해당하는 날짜를 반환하는 TemporalAdjuster를 반환함. |
lastDayOfMonth | 현재 달의 마지막 날짜를 반환하는 TemporalAdjuster를 반환함. |
lastDayOfNexMonth | 다음 달의 마지막 날짜를 반환하는 TemporalAdjuster를 반환함. |
lastDayOfYear | 올해의 마지막 날짜를 반환하는 TemporalAdjuster를 반환함. |
lastInMonth | ‘3월의 마지막 화요일’처럼 현재 달의 마지막 요일에 해당하는 날짜를 반환하는 TemporalAdjuster를 반환함. |
next | 현재 날짜 이후로 지정한 요일이 처음으로 나타는 날짜를 반환하는 TemporalAdjuster를 반환함(현재 날짜는 포함하지 않음.) |
previous | 현재 날짜 이후로 역으로 날짜를 거슬러 올라가며 지정한 요일이 처음으로 나타나는 날짜를 반환하는 TemporalAdjuster를 반환함(현재 날짜는 포함하지 않음. |
nextOrSame | 현재 날짜 이후로 지정한 요일이 처음으로 나타나는 날짜를 반환하는 TemporalAdjuster를 반환함(현재 날짜도 포함.) |
previousOrSame | 현재 날짜 이후로 역으로 날짜를 거슬러 올라가며 지정한 요일이 처음으로 나타나는 날짜를 반환하는 TemporalAdjuster를 반환함(현재 날짜도 포함.) |
커스텀 TemporalAdjuster 구현
1 | public class CustomTemporalAdjister { |
결과 화면1
2
3
4
5
6
72019-06-23
2019-06-30
2019-07-01
2019-07-05
2019-07-08
2019-07-12
2019-07-15
날짜와 시간 객체 출력과 파싱
DateTimeFomatter
를 이용해서 날짜나 시간을 특정 형식의 문자열로 만들 수 있다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public class DateFormatterExamples {
public static void main(String[] args) {
useDateFormatter();
}
private static void useDateFormatter() {
LocalDate date = LocalDate.of(2019, 6, 23);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
DateTimeFormatter koreaFormatter = DateTimeFormatter.ofPattern("d. MMMM yyyy", Locale.KOREA);
System.out.println(date.format(DateTimeFormatter.ISO_LOCAL_DATE));
System.out.println(date.format(formatter));
System.out.println(date.format(koreaFormatter));
DateTimeFormatter complexFormatter = new DateTimeFormatterBuilder()
.appendText(ChronoField.DAY_OF_MONTH)
.appendLiteral(". ")
.appendText(ChronoField.MONTH_OF_YEAR)
.appendLiteral(" ")
.appendText(ChronoField.YEAR)
.parseCaseInsensitive()
.toFormatter(Locale.KOREA);
System.out.println(date.format(complexFormatter));
}
}
결과 화면1
2
3
42019-06-23
23/06/2019
23. 6월 2019
23. 6월 2019