자바 8이전의 날짜와 시간 정보는 Date, Calendar, SimpleDateFormatter 클래스를 이용왔지만,
이러한 기존 날짜를 표현하는 라이브러리들은 다양한 문제를 가져왔다.
기존 Date, Calendar 등 날짜/시간 표현식의 문제점
- 변경이 가능하다.
: 날짜/시간 유형은 변경 불가능한 유형으로 유용하게 모델링 되는 자연 값이다.
Date와 같은 기존 클래스는 mutable 하기 때문에 thread safe 하지 않아 멀티 쓰레드 환경에서 안전하게 사용하기 어렵다.
- 클래스의 이름이 명확하지 않다.
: Date인데 시간까지 설정이 가능하다는 것이 프로그램을 모호하게 만든다.
- 월을 표현할 때 +1을 해주어야한다.
: type safe 하지 않으며, 버그 발생의 여지가 있다.
그 외에도 Date 클래스의 다양한 문제점은 해당 블로그에서 확인 가능 하다.
https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/
https://codeblog.jonskeet.uk/2015/05/05/common-mistakes-in-datetime-formatting-and-parsing/
그렇다면 날짜/시간 관련해서 어떤 API를 사용해야할까?
시간은 기계시간/사람시간으로 구분할 수 있다.
1. 기계시간 표현
Instant
: 메소드 시간 비교 및 서버 비지니스로직 등에 사용할 수 있다.
Instant instant = Instant.now();
System.out.println(instant); // 기준시 UTC, GMT
System.out.println(instant.atZone(ZoneId.of("Asia/Seoul"))); // 기준시 설정
System.out.println(instant.atZone(ZoneId.systemDefault())); // 현재 서버를 기준시로
// 2022-11-16T11:42:47.296444Z
// 2022-11-16T20:42:47.296444+09:00[Asia/Seoul]
// 2022-11-16T20:42:47.296444+09:00[Asia/Seoul]
2. 사람시간 표현
LocalDateTime
: 해당 서버의 시간이 표시 되므로 클라이언트에서 보여지는 시간을 표현할 때 주로 사용한다.
ZonedDateTime
: LocalDateTime + 타임존 설정 기능을 제공합니다.
LocalDateTime now = LocalDateTime.now(); // 현재 서버에 대한 시간이 표시됨
System.out.println(now);
LocalDateTime birthDay = LocalDateTime.of(1999, Month.JANUARY, 20,0,0,0);
System.out.println(birthDay);
ZonedDateTime nowInKorea = ZonedDateTime.now(ZoneId.of("Asia/Seoul")); // LocalDateTime + Time Zone(시간대)
System.out.println(nowInKorea);
// format
DateTimeFormatter isoLocalDate = DateTimeFormatter.ISO_LOCAL_DATE;
System.out.println(now.format(isoLocalDate));
System.out.println(now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS")));
// parse
LocalDate parse = LocalDate.parse("1999.01.20", DateTimeFormatter.ofPattern("yyyy.MM.dd"));
System.out.println(parse);
// result
// 2022-11-16T20:53:25.736113
// 1999-01-20T00:00
// 2022-11-16T20:53:25.736461+09:00[Asia/Seoul]
// 2022-11-16
// 2022-11-16 20:53:25:736
// 1999-01-20
DateTimeFormatter
ofLocalizedDate(dateStyle) | '2011-12-03' |
ofLocalizedTime(timeStyle) | '10:15:30' |
ofLocalizedDateTime(dateTimeStyle) | '3 Jun 2008 11:05:30' |
ofLocalizedDateTime(dateStyle,timeStyle) | '3 Jun 2008 11:05' |
BASIC_ISO_DATE | '20111203' |
ISO_LOCAL_DATE | '2011-12-03' |
ISO_OFFSET_DATE | '2011-12-03+01:00' |
ISO_DATE | '2011-12-03+01:00'; '2011-12-03' |
ISO_LOCAL_TIME | '10:15:30' |
ISO_OFFSET_TIME | '10:15:30+01:00' |
ISO_TIME | '10:15:30+01:00'; '10:15:30' |
ISO_LOCAL_DATE_TIME | '2011-12-03T10:15:30' |
ISO_OFFSET_DATE_TIME | 2011-12-03T10:15:30+01:00' |
ISO_ZONED_DATE_TIME | '2011-12-03T10:15:30+01:00[Europe/Paris]' |
ISO_DATE_TIME | '2011-12-03T10:15:30+01:00[Europe/Paris]' |
ISO_ORDINAL_DATE | '2012-337' |
ISO_WEEK_DATE | 2012-W48-6' |
ISO_INSTANT | '2011-12-03T10:15:30Z' |
RFC_1123_DATE_TIME | 'Tue, 3 Jun 2008 11:05:30 GMT' |
https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
3. 날짜 사이 간격 구하기
기계시간 - Duration
Instant now = Instant.now();
Instant plus = now.plus(10, ChronoUnit.SECONDS);
Duration between = Duration.between(now, plus);
System.out.println(between.getSeconds());
System.out.println(ChronoUnit.SECONDS.between(now, plus));
// result
// 10
// 10
사람시간 - Period
LocalDate today = LocalDate.now();
LocalDate thisYearBirthDay = LocalDate.of(2023, Month.JANUARY, 20);
// 사이의 총 년,월,일 구하기
Period period = Period.between(today, thisYearBirthDay);
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
// 사이의 총 일 구하기
System.out.println(ChronoUnit.DAYS.between(today, thisYearBirthDay));
// result
// 0
// 2
// 4
// 65
- 예제로 비밀번호를 30일 마다 변경해야하는 정책이 있다는 가정하에 비밀번호 경과 일을 체크하는 메서드를 만들어봤다.
private static Boolean changePwdYnCheck(LocalDateTime lastDate) {
LocalDateTime now = LocalDateTime.now();
now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS"));
// 변경 되어야 하는 날짜 (lastDate + 30)
LocalDateTime compareDttm = lastDate.plusDays(30);
int compare = compareDttm.compareTo(now);
if(compare >= 0){ // 변경 되어야 함
return true;
}else{
return false;
}
}
'JAVA > Modern JAVA' 카테고리의 다른 글
[JAVA 8] 분할 가능한 Iterator인 Spliterator 인터페이스 (0) | 2022.11.01 |
---|---|
[JAVA 8] 함수형(Functional) 인터페이스 와 람다(Lambda)표현식 (0) | 2022.10.12 |