날짜와 시간을 계산하는 것은 단순하게 생각하면 쉬워보이지만, 실제로는 매우 어렵고 복잡하다.
1. 날짜와 시간 차이 계산
특정 날짜에서 다른 날짜까지의 정확한 일수를 계산하는 것은 생각보다 복잡하다. 윤년, 각 달의 일수 등을 모두 고려해서 계산하는 것은 쉽지 않다.
2. 윤년 계산
지구가 태양을 한바퀴 도는 시간과 1년 365일의 차이가 있기 때문에, 4년마다 하루를 추가하는 윤년을 도입한다. 하지만 그 윤년에도 다양한 예외사항이 있기 때문에, 계산하는 것이 쉬운일이 아니다.
3. 일광 절약 시간 변환
보통 3월에서 10월은 태양이 일찍 뜨고, 나머지는 상대적으로 태양이 늦게 뜬다. 시간도 여기에 맞추어 1시간 앞당기거나
늦추는 제도를 일과 절약 시간제 또는 썸머 타임이라고 한다. 일광 절약 시간은 국가나 지역에 따라 적용 여부와 시작 및 종료 날짜가 다르다. 이와 같은 예외사항으로 정확하게 계산하는 것은 매우 어렵다.
참고로 대한민국은 1988년 이후로 시행하지 않는다.
4. 타임존 계산
세계는 다양한 타임존으로 나뉘어 있으며, 각 타임존은 UTC(협정 세계시) 로부터의 시간 차이로 정의된다. 타임존 간의 날짜와 시간 변환을 정확히 계산하는 것은 복잡하다.
결론
이러한 복잡성 때문에 대부분의 현대 개발 환경에서는 날짜와 시간을 처리하기 위해 잘 설계된 라이브러리르를 사용해야 한다.
자바 날짜와 시간 라이브러리 역사
JDK 1.0(java.util.Date)
문제점
타임존 처리 부족
불편한 날짜 시간 연산
불변 객체 부재
해결책
JDK 1.1 에서 java.util.Calendar 클래스 도입으로 타임존 지원 개선
날짜 시간 연산을 위한 추가 메서드 제공
JDK 1.1(java.util.Calendar)
문제점
사용성 저하
성능 문제
불변 객체 부재
해결책
Joda-Time 오픈소스 라이브러리 도입으로 사용성, 성능, 불변성 문제 해결
Joda-Time
문제점
표준 라이브러리가 아님
해결책
자바 8에서 java.time 패키지를 표준 API 로 도입
JDK 8 (java.time 패키지)
java.time 패키지는 이전 API 문제를 해결하면서, 사용성, 성능, 스레드 안전성, 타임존 처리 등에서 크게 개선되었다.
LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant 등의 클래스를 포함한다.
Joda-Time 의 많은 기능을 표준 플랫폼으로 가져왔다.
자바 날짜와 시간 라이브러리 소개
자바 날짜와 시간 라이브러리는 자바 공식 문서가 제공하는 다음 표 하나로 정리할 수 있다.
LocalDate, LocalTime, LocalDateTime
LocalDate : 날짜만 표현할 때 사용한다.
LocalTime : 시간을 표현할 떄 사용한다.
LocalDateTime : LocalDate, LocalTime 을 합한 개념이다.
앞에 Local (현지의, 특정 지역의) 이 붙는 이유는 세계 시간대를 고려하지 않아서 타임존이 적용되지 않기 때문이다.
특정 지역의 날짜와 시간만 고려할 때 사용한다.
애플리케이션 개발시 국내 서비스만 고려할 때
ZonedDateTime, OffsetDateTime
ZonedDateTime : 시간대를 고려한 날짜와 시간을 표현할 때 사용한다. 여기에는 시간대를 표현하는 타임존과 오프셋이 포함된다.
OffsetDateTime : 시간대를 고려한 날짜와 시간을 표현할 때 사용한다. 여기에는 타임존이 없고, UTC 로 부터의 시간대 차이가 고정인 오프셋만 포함된다.
Asia/Seoul 과 같은 타임존 안에는 일광 절약 시간제에 대한 정보와 UTC+9:00와 같은 UTC 로 부터 시간 차이인 오프셋 정보를 모두 포함하고 있다.
일광 절약 시간제를 알려면 타임존을 알아야 한다. 따라서 ZonedDateTime 은 일광 절약 시간제를 함께 처리한다. 반면에 타임존을 알 수 없는 OffsetDateTime 은 일광 절약 시간제를 처리하지 못한다.
Instant
Instant 는 UTC 를 기준으로 하는, 시간의 한 지점을 나타낸다. Instant 는 날짜와 시간을 나노초 정밀도로 표현하며, 1970. 1. 1 00:00:00 를 기준으로 경과한 시간이 계산된다.
쉽게 이야기해서 Instant 내부에는 초 데이터만 들어있다.
따라서 날짜와 시간을 계산하는 용도로는 적합핮지 않다.
Period, Duration
시간의 개념은 크게 2가지로 표현할 수 있다.
특정 시점에 시간(시각)
이 프로젝트는 2013년 8월 16일 까지 완료해야해
다음 회의는 11시 30분에 진행한다.
내 생일은 8월 16일이야.
시간의 간격(기간)
앞으로 4년은 더 공부해야 해
이 프로젝트는 3개월 남았어
라면은 3분 동안 끓어야 해
Period, Duration 은 시간의 간격(기간) 을 표현하는데 사용된다.
Period
두 날짜 사이의 간격을 년, 월, 일 단위로 나타낸다.
Duration
두 시간 사이의 간격을 시, 분, 초 단위로 나타낸다.
기본 날짜와 시간 - LocalDateTime
LocalDate
package time;
import java.time.LocalDate;
public class LocalDataMain {
public static void main(String[] args) {
// 생성
LocalDate nowDate = LocalDate.now();
LocalDate ofDate = LocalDate.of(1997, 7, 14);
System.out.println("오늘 날짜 = " + nowDate);
System.out.println("지정 날짜 = " + ofDate);
// 계산(불변) -> 반환값을 받아야 한다.
ofDate = ofDate.plusDays(10);
System.out.println("지정 날짜 + 10D = " + ofDate);
}
}
LocalTime
package time;
import java.time.LocalTime;
public class LocalTimeMain {
public static void main(String[] args) {
// 생성
LocalTime nowTime = LocalTime.now();
LocalTime ofTime = LocalTime.of(9, 10, 30);
System.out.println("현재 시간 = " + nowTime);
System.out.println("지정 시간 = " + ofTime);
// 계산
LocalTime ofTimePlus = ofTime.plusSeconds(30);
System.out.println("지정 시간 + 30초 = " + ofTimePlus);
}
}