Java8 java.time
java.time 패키지
자바에서의 날짜 및 시간 처리
- JDK 1.0에서는 Date 클래스를 사용하여 날짜에 관한 처리를 수행했다. 하지만
Date 클래스
는 현재 대부분의 메소드가 사용을 권장하지 않고(deprecated
) 있다. JDK 1.1부터 새롭게 제공된
Calendar 클래스
는 날짜와 시간에 대한 정보를 손쉽게 얻을 수 있었다. 하지만 Calendar 클래스는 다음과 같은 문제점을 가지고 있다.Calendar 인스턴스는 불변 객체(immutable object)가 아니라서
값이 수정될 수 있다
.윤초(leap second)
와 같은 특별한 상황을 고려하지 않는다.Calendar 클래스에서는 월(month)을 나타낼 때 1월부터 12월을
0부터 11까지로 표현
해야 하는 불편함이 있다.
- 따라서 많은 자바 개발자들은 Calendar 클래스뿐만 아니라 더 나은 성능의 Joda-Time이라는 라이브러리를 함께 사용해 왔다.
- Java SE 8 버전에서는 이러한
Joda-Time 라이브러리를 발전
시킨새로운 날짜와 시간 API인 java.time 패키지
를 제공한다. java.time 패키지는 위와 같은 문제점을 모두 해결했으며, 다양한 기능을 지원하는 다수의 하위 패키지를 포함하고 있다.
java.time 패키지
Java SE 8부터 제공되는
java.time 패키지
에는 자바에서날짜와 시간을 다루는 데 사용되는 필수 클래스들이 포함
되어 있다. 또한, 다음과 같은 다양한 기능을 하는하위 패키지
를 포함하고 있다.java.time.chrono : ISO-8601에 정의된 표준 달력 이외의 달력 시스템을 사용할 때 필요한 클래스들
java.time.format : 날짜와 시간에 대한 데이터를 구문분석하고 형식화하는 데 사용되는 클래스들
java.time.temporal : 날짜와 시간에 대한 데이터를 연산하는 데 사용되는 보조 클래스들
java.time.zone : 타임 존(time-zone)과 관련된 클래스들
java.time 패키지는 기존에 사용되던
Calendar 클래스의 단점을 보완
하였다. 따라서 해당 패키지에 속하는 모든 클래스의 인스턴스는불변 객체(immutable object)로 생성
된다. 즉,java.time 패키지에 포함되는 클래스의 메소드들은 모두 새로운 객체를 생성하여 반환
하고 있다.
java.time 패키지의 구성 클래스
- 기존의 Calendar 클래스는 날짜와 시간을 한 번에 표현했지만,
java.time 패키지에서는 별도로 구분하여 처리
한다. LocalDate 클래스
는날짜
를 표현할 때 사용하며,LocalTime 클래스
는시간
을 표현할 때 사용한다.- 또한,
기존의 Calendar 클래스
처럼 날짜와 시간을 한 번에 표현하고 싶을 때는LocalDateTime 클래스
를 사용한다. ZonedDateTime 클래스
는특정 타임 존(time-zone)
에 해당하는 날짜와 시간을 다루는 데 사용한다.- 또한,
기존의 Date 클래스
와 비슷한 용도로 사용되는Instant 클래스
가 있다. Instant 클래스는 특정 시점의 날짜와 시간을 나노초(nanosecond) 단위로 표현하는타임스탬프(time-stamp)
를 다루는 데 사용된다. Period 클래스
는두 날짜 사이의 차이
를 표현하는 데 사용되며,Duration 클래스
는두 시각 사이의 차이
를 표현하는 데 사용된다.
LocalDate와 LocalTime
LocalDate 클래스와 LocalTime 클래스
- LocalDate 클래스는 날짜를 표현하는 데 사용되며, LocalTime 클래스는 시간을 표현하는 데 사용된다.
- java.time 패키지에 포함된 대부분의 클래스들은 이 두 클래스를 확장한 것이 많으므로, 우선 이 두 클래스를 잘 이해하는 것이 중요하다.
날짜와 시간 객체의 생성
- LocalDate와 LocalTime 클래스는
객체를 생성
하기 위해서 now()와 of() 메소드라는 클래스 메소드를 제공한다. now() 메소드
는현재의 날짜와 시간
을 이용하여 새로운 객체를 생성하여 반환한다.- 하지만
of() 메소드
는 전달된 인수를 가지고특정 날짜와 시간
을 표현하는 새로운 객체를 생성하여 반환한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.time.*;
public class prog {
public static void main(String[] args){
LocalDate today = LocalDate.now();
LocalTime present = LocalTime.now();
System.out.println(today + " " + present);
// static LocalDate of(int year, int month, int dayOfMonth)
LocalDate birthDay = LocalDate.of(1982, 02, 19);
// static LocalTime of(int hour, int minute, int second, int nanoOfSecond)
LocalTime birthTime = LocalTime.of(02, 02, 00, 100000000);
System.out.println(birthDay + " " + birthTime);
}
}
of() 메소드
는 위의 예제에서 사용된 메소드 시그니처 이외에도다양한 형태가 오버로딩
되어 제공된다.
날짜와 시간 객체에 접근하기
- LocalDate와 LocalTime 클래스는 특정 필드의 값을 가져오기 위해서 다음과 같이 다양한
getter 메소드를 제공
한다. LocalDate 클래스
에서 제공하는 대표적인 getter 메소드는 다음과 같다.
메소드 | 설명 |
---|---|
int get(TemporalField field) | |
long getLong(TemporalField field) | 해당 날짜 객체의 명시된 필드의 값을 int형이나 long형으로 반환한다. |
int getYear() | 해당 날짜 객체의 연도(YEAR) 필드의 값을 반환한다. |
int getMonthValue() | 해당 날짜 객체의 월(MONTH_OF_YEAR) 필드의 값을 반환한다. (1~12) |
int getDayOfMonth() | 해당 날짜 객체의 일(DAY_OF_MONTH) 필드의 값을 반환한다. (1~31) |
int getDayOfYear() | 해당 날짜 객체의 일(DAY_OF_YEAR) 필드의 값을 반환한다.(1~365, 윤년이면 366) |
Month getMonth() | 해당 날짜 객체의 월(MONTH_OF_YEAR) 필드의 값을 Month 열거체를 이용하여 반환한다. |
DayOfWeek getDayOfWeek() | 해당 날짜 객체의 요일(DAY_OF_WEEK) 필드의 값을 DayOfWeek 열거체를 이용하여 반환한다. |
기존의 Calendar 클래스
에서는 1월을 0으로 표현하여월의 범위가 0~11
이었으며, 요일은일요일부터 1
로 표현했다.- 하지만
java.time 패키지
에서는 1월을 1로 표현하여월의 범위가 1~12
가 되었으며, 요일은월요일부터 1
로 표현하도록 변경되었다. - Calendar 클래스와 java.time 패키지의 클래스를 같이 사용할 때에는 특히 위와 같은 차이점에 주의해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.time.*;
import java.time.temporal.*;
public class prog {
public static void main(String[] args){
LocalDate today = LocalDate.now();
System.out.println("올해는 " + today.getYear() + "년입니다.");
System.out.println("이번달은 " + today.getMonthValue() + "월입니다.");
System.out.println("오늘은 " + today.getDayOfWeek() + "입니다.");
System.out.println("오늘은 1년 중 " + today.get(ChronoField.DAY_OF_YEAR) + "일째 날입니다.");
}
}
LocalTime 클래스
에서 제공하는 대표적인 getter 메소드는 다음과 같다.
메소드 | 설명 |
---|---|
int get(TemporalField field) | |
long getLong(TemporalField field) | 해당 시간 객체의 명시된 필드의 값을 int형이나 long형으로 반환한다. |
int getHour() | 해당 시간 객체의 시(HOUR_OF_DAY) 필드의 값을 반환한다. |
int getMinute() | 해당 시간 객체의 분(MINUTE_OF_HOUR) 필드의 값을 반환한다. |
int getSecond() | 해당 시간 객체의 초(SECOND_OF_MINUTE) 필드의 값을 반환한다. |
int getNano() | 해당 시간 객체의 나노초(NANO_OF_SECOND) 필드의 값을 반환한다. |
1
2
3
4
5
6
7
8
9
10
import java.time.*;
public class prog {
public static void main(String[] args){
LocalTime present = LocalTime.now();
System.out.println("현재 시간은 " +
present.getHour() + "시 " + present.getMinute() + "분입니다.");
}
}
TemporalField 인터페이스
TemporalField 인터페이스
는 월(month-of-year)과 시(hour-of-day)와 같이날짜와 시간과 관련된 필드를 정의해 놓은 인터페이스
이다. 이 인터페이스를구현
하여 날짜와 시간을 나타낼 때 사용하는열거체가 바로 ChronoField
이다.java.time 패키지를 구성하는 클래스의 메소드
에서는이 열거체를 이용
하여 날짜와 시간을 처리하고 있다.- ChronoField 열거체에 정의된 대표적인 열거체 상수는 다음과 같다.
열거체 상수 | 설명 |
---|---|
ERA | 시대 |
YEAR | 연도 |
MONTH_OF_YEAR | 월 |
DAY_OF_MONTH | 일 |
DAY_OF_WEEK | 요일 (월요일:1, 화요일:2, …, 일요일:7) |
AMPM_OF_DAY | 오전/오후 |
HOUR_OF_DAY | 시(0~23) |
CLOCK_HOUR_OF_DAY | 시(1~24) |
HOUR_OF_AMPM | 시(0~11) |
CLOCK_HOUR_OF_AMPM | 시(1~12) |
MINUTE_OF_HOUR | 분 |
SECOND_OF_MINUTE | 초 |
DAY_OF_YEAR | 해당 연도의 몇 번째 날 (1~365, 윤년이면 366) |
EPOCH_DAY | EPOCH(1970년 1월 1일)을 기준으로 몇 번째 날 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.time.*;
import java.time.temporal.ChronoField;
public class prog {
public static void main(String[] args){
LocalTime present = LocalTime.now();
String ampm;
if (present.get(ChronoField.AMPM_OF_DAY) == 0) {
ampm = "오전";
} else {
ampm = "오후";
}
System.out.println("지금은 " + ampm + " " + present.get(ChronoField.HOUR_OF_AMPM) + "시입니다.");
}
}
날짜와 시간 객체의 필드값 변경
- LocalDate와 LocalTime 클래스는 날짜와 시간
객체에 접근하여 특정 필드의 값을 변경
하기 위해서with() 메소드
를 사용한다. with() 메소드를 사용하면 값이 변경될 필드를사용자가 직접 명시할 수 있다
. - 또한, 특정 필드의 값을 변경하기 위해
미리 정의되어 제공되는 다양한 with() 메소드
를 사용할 수도 있다. LocalDate 클래스
에서 제공하는 with() 메소드는 다음과 같다.
메소드 | 설명 |
---|---|
LocalDate with(TemporalField field, long newValue) | 해당 날짜 객체에서 특정 필드를 전달된 새로운 값으로 설정한 새로운 날짜 객체를 반환한다. |
LocalDate withYear(int year) | 해당 날짜 객체에서 연도(YEAR) 필드를 전달된 새로운 값으로 설정한 새로운 날짜 객체를 반환한다. |
LocalDate withMonth(int month) | 해당 날짜 객체에서 월(MONTH_OF_YEAR) 필드를 전달된 새로운 값으로 설정한 새로운 날짜 객체를 반환한다. |
LocalDate withDayOfMonth(int dayOfMonth) | 해당 날짜 객체에서 일(DAY_OF_MONTH) 필드를 전달된 새로운 값으로 설정한 새로운 날짜 객체를 반환한다. |
LocalDate withDayOfYear(int dayOfYear) | 해당 날짜 객체에서 DAY_OF_YEAR 필드를 전달된 새로운 값으로 설정한 새로운 날짜 객체를 반환한다. |
1
2
3
4
5
6
7
8
9
10
11
import java.time.*;
public class prog {
public static void main(String[] args){
LocalDate today = LocalDate.now();
System.out.println("올해는 " + today.getYear() + "년입니다.");
LocalDate otherDay = today.withYear(1982);
System.out.println("올해는 " + otherDay.getYear() + "년입니다.");
}
}
LocalTime 클래스
에서 제공하는 with() 메소드는 다음과 같다.
메소드 | 설명 |
---|---|
LocalTime with(TemporalField field, long newValue) | 해당 시간 객체에서 특정 필드를 전달된 새로운 값으로 설정한 새로운 시간 객체를 반환한다. |
LocalTime withHour(int hour) | 해당 시간 객체에서 시(HOUR_OF_DAY) 필드를 전달된 새로운 값으로 설정한 새로운 시간 객체를 반환한다. |
LocalTime withMinute(int minute) | 해당 시간 객체에서 분(MINUTE_OF_HOUR) 필드를 전달된 새로운 값으로 설정한 새로운 시간 객체를 반환한다. |
LocalTime withSecond(int second) | 해당 시간 객체에서 초(SECOND_OF_MINUTE) 필드를 전달된 새로운 값으로 설정한 새로운 시간 객체를 반환한다. |
LocalTime withNano(int nanoOfSecond) | 해당 시간 객체에서 나노초(NANO_OF_SECOND) 필드를 전달된 새로운 값으로 설정한 새로운 시간 객체를 반환한다. |
1
2
3
4
5
6
7
8
9
10
11
import java.time.*;
public class prog {
public static void main(String[] args){
LocalTime present = LocalTime.now();
System.out.println("현재 시간은 " + present.getHour() + "시입니다.");
LocalTime otherTime = present.withHour(8);
System.out.println("현재 시간은 " + otherTime.getHour() + "시입니다.");
}
}
- with() 메소드 이외에도 특정 필드의 값을 더하거나 뺄 수 있는 다양한
plus()와 minus() 메소드
도 제공된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.time.*;
import java.time.temporal.*;
public class prog {
public static void main(String[] args){
LocalTime present = LocalTime.now();
System.out.println("현재 시간은 " + present.get(ChronoField.HOUR_OF_DAY) + "시입니다.");
LocalTime otherTime = present.plus(2, ChronoUnit.HOURS);
System.out.println("바뀐 시간은 " + otherTime.getHour() + "시입니다.");
LocalTime anotherTime = present.minus(6, ChronoUnit.HOURS);
System.out.println("바뀐 시간은 " + anotherTime.getHour() + "시입니다.");
}
}
ChronoField.HOUR_OF_DAY
는TemporalField
를 구현한 열거체이므로LocalTime
객체의get
메서드의 인자로 사용할 수 있다.
날짜와 시간 객체의 비교
LocalDate와 LocalTime 클래스
에도 객체를 비교할 수 있는compareTo() 메소드가 오버라이딩
되어 있e다. 하지만 더욱 편리하게 날짜와 시간 객체를 서로 비교할 수 있도록 다음과 같은 메소드를 제공한다.isEqual() 메소드
: equals() 메소드와는 달리오직 날짜만을 비교
한다.(LocalDate 클래스에서만 제공)isBefore() 메소드
: 두 개의날짜와 시간 객체를 비교
하여 현재 객체가 명시된 객체보다 앞선 시간인지를 비교한다.isAfter() 메소드
: 두 개의날짜와 시간 객체를 비교
하여 현재 객체가 명시된 객체보다 늦은 시간인지를 비교한다.
1
2
3
4
5
6
7
8
9
10
11
12
import java.time.*;
public class prog {
public static void main(String[] args){
LocalDate today = LocalDate.now();
LocalDate otherDay = LocalDate.of(1982, 02, 19);
System.out.println(today.compareTo(otherDay));
System.out.println(today.isBefore(otherDay));
System.out.println(today.isEqual(otherDay));
}
}
compareTo() 메소드
는LocalDate 객체 간의 비교를 수행
하고,그 차이를 반환
한다. 이 메서드는Comparable 인터페이스
를 구현하여 비교가 가능하도록 한다. 반환 값이 0보다 작으면 호출된 객체가 인자로 전달된 객체보다 이전에 있음을 나타내고, 0이면 두 날짜가 같음을 나타낸다. 반면에 반환 값이 0보다 크면 호출된 객체가 인자로 전달된 객체보다 나중에 있음을 나타낸다.- 따라서 여기서 반환된 42는 현재 날짜인 today가 1982년 2월 19일인 otherDay보다 42일 뒤에 있다는 것을 의미한다.