Joda-Time
Java 8 이전에는 Date 관련 API들이 가지는 문제들을 해결하기 위해서, Joda-Time 이라는 라이브러리를 사용했습니다.
그래서 Java 8부터는 Joda-Time이 자바 표준 라이브러리로 들어왔습니다.
Joda-Time는 다음과 같은 클래스를 지원합니다.
- Instance
- LocalDate & LocalTime
- DateTime
- Duration & Period
- ...
기존 Date 관련 API의 문제점
Java 8 이전에 사용하던 Date 관련 클래스는 Date, Calander, SimpleDateFormat 등이 있습니다. 하지만 많은 문제가 있어서, 자바 8 버전 이후 부터는 새로운 날짜 관련 API들을 제공합니다.
기존 클래스들의 문제입니다.
1. 부적절한 클래스, 메소드 이름
- Date 클래스의 경우, TimeStamp 방식으로 동작하고 시간을 내재하고 있음. 그런데 ClassName은 Date임
- date.getTime()을 하면 1970.1.1을 기준으로 밀리세컨을 반환함. -> 메소드의 결과를 파악하기 어려움
2. Thread safety 하지 않다.
- Date 클래스의 경우 mutable 하기 때문에 다른 Thread에서 값을 참조하고 변경할 수 있음 -> thread safe하지 않음
3. 버그가 발생할 여지가 많다.
- Calander 클래스의 경우 입력값의 month가 0이 1월로 처리됨 -> 그래서 Calander.SETEMBER 같은 상수를 사용해야함, 그리고 DB 데이터랑 연결하면서 서로 다르게 해석됨. 문제가 발생할 여지가 너무 많음
- Parameter Type으로 Enum이 아니라 int를 사용하므로, month에 음수가 들어올 수도 있음 (Type safety 하지 않음)
사실 언급한 것보다 훨씬 더 많은 문제가 있지만 생략하고 넘어가겠습니다.
Instant 클래스
Joda-Time은 기계의 시간과 사람의 시간을 분리 합니다. 예를 들어, date.getTime()은 1970.1.1을 기준으로 밀리세컨을 반환합니다. 즉, 1520350393 이런 결과 값을 받는데, 이는 사람이 읽을 수 없는 기계식 시간입니다.
Instant는 특정 시간을 셋팅할 수는 없습니다. 기계식 시간을 사용할 때 편리한 클래스입니다.
Instasnt.now()는 현재 시간을 UTC 기준으로 반환합니다.
Instant now = Instant.now();
System.out.println(now); // 2022-03-16T13:36:12.391103800Z
Instant 클래스의 메서드를 사용하면 기계식으로 시간을 연산하기 좋습니다.
System.out.println(now.getEpochSecond()); // 1647438625
System.out.println(now.toEpochMilli()); // 1647438625212
Instant instantA = now.plusMillis(1000); // +1000ms
Instant instantB = now.minusMillis(1000); // -1000ms
ZoneId & ZonedDateTime 클래스
ZonedId 클래스를 사용하면 타임존을 담고 사용할 수 있습니다. ZonedDateTime으로 해당 타임존을 Set할 수 있습니다.
ZoneId zone = ZoneId.systemDefault();
System.out.println(zone); // Asia/Seoul
ZonedDateTime zonedDateTime = now.atZone(zone);
System.out.println(zonedDateTime); // 2022-03-16T22:36:12.391103800+09:00[Asia/Seoul]
LocalDateTime 클래스
LocalDateTime은 시스템의 타임존을 참고해서 로컬 시간을 가져옵니다.
LocalDateTime now = LocalDateTime.now();
System.out.println(now); // 2022-03-16T22:42:14.080317
특정 시간을 만들 수도 있습니다.
LocalDateTime day = LocalDateTime.of(1997, Month.JULY, 17, 0, 0, 0);
Period & Duration 클래스
Period와 Duration 클래스는 기간을 사용하는 클래스입니다.
Period를 사용하면, Human식 날짜 사이의 기간을 구할 수 있습니다.
LocalDate today = LocalDate.now();
LocalDate lastDay = LocalDate.of(2022, Month.MARCH, 31);
Period period = Period.between(today, lastDay);
System.out.println(period.getMonths()); // 0
System.out.println(period.getDays()); // 15
Duration을 사용하면, 기계식 날짜 사이의 기간을 구할 수 있습니다.
Instant now = Instant.now();
Instant plus = now.plus(3, ChronoUnit.MINUTES);
Duration duration = Duration.between(now, plus);
System.out.println(duration.getSeconds()); // 180
DateTimeFormatter 클래스
DateTimeFormatter 클래스에는 다양한 날짜/시간의 포맷이 미리 정의되어 있습니다.
-> https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#predefined
DateTimeFormatter를 사용해서 간편하게 LocalDateTime의 형식을 변경할 수 있습니다.
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter iso = DateTimeFormatter.ISO_DATE;
System.out.println(now.format(iso)); // 2022-03-16
custom으로 패턴을 정의해서 쉽게 사용할 수도 있습니다.
DateTimeFormatter customFormat = DateTimeFormatter.ofPattern("MM/dd:HH");
System.out.println(now.format(customFormat)); // 03/16:11
parse()를 사용하면, 다시 DateTimeFormatter를 사용해서 문자열을 날짜 형태로 파싱할 수도 있습니다.
DateTimeFormatter customFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd:HH");
System.out.println(now.format(customFormat)); // 2022/03/16:11
LocalDateTime parsedTime = LocalDateTime.parse("2022/03/16:11", customFormat);
System.out.println(parsedTime); // 2022-03-16T11:00
<참고> Immutable
자바 8 이전에 사용하던 Date 클래스를 생각해서, Zoda-Time 라이브러리 내부 클래스도, plus, minus 등의 메서드가 객체 내부의 상태를 변경한다고 생각하시면 안됩니다.
다음과 같은 코드는 아무런 변화도 일어나지 않습니다.
Instant now = Instant.now();
System.out.println(now); // 2022-03-16T14:35:00.341260100Z
now.plusMillis(1000);
System.out.println(now); // 2022-03-16T14:35:00.341260100Z
now.minusMillis(1000);
System.out.println(now); // 2022-03-16T14:35:00.341260100Z
Zoda-Time 내부 클래스는 Immutable한 불변 객체이기 때문에, 새로운 객체에 값을 할당해서 사용해야 합니다.
Instant after = now.plusSeconds(30);
감사합니다.
'Language > Java' 카테고리의 다른 글
Java - Concurrent Programming (Runnable, Executor, Callable, Future 등) (0) | 2022.04.03 |
---|---|
Java - Arrays.asList vs List.of 차이 (완벽 정리)! (1) | 2022.03.27 |
Java 8 - Optional이란? (0) | 2022.03.12 |
Java 8 - Stream이란? (+ ParallelStream) (0) | 2022.03.11 |
Java 8 - 인터페이스의 default method, static method 사용! (0) | 2022.03.09 |