JAVA/Modern JAVA

[JAVA 8] 날짜/시간 표현 (Instant, ZonedDateTime, LocalDateTime, Period)

빅콜팝 2022. 11. 16. 21:14
728x90
반응형

자바 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;
    }
}
728x90
반응형