[Java] Date


Date

java.util.Date

일반적으로 날짜와 시간을 저장할 때 사용

ex) 2020-04-03 09:58:30

TimeStamp

java.sql.Timestamp

date보다 정밀한 시간을 요구할 때 사용. 시스템간의 프로세스 시간, 우선순위 정할때 밀리세컨드 이하까지 사용하기 위해 사용한다.

ex) 2020-04-03 09:58:30.000000000

Issue

자바에서 기본적 으로 제공하는 Date와 Calendar를 사용하면 안되는 이유

오랫동안 제공된 JDK 1.0의 Date 클래스, 1.1 이후의 Calendar 클래스에는 문제점들이 있다.

  1. 컴파일 시점에서 오류를 확인할 수 없다.
  2. 월 계산
  3. 불변이 아니다.
  4. 상수 필드 남용
  5. 일관성 없는 요일 상수
  6. Date와 Calendar 객체의 역할 분담
  7. 기타 java.util.Date 하위 클래스의 문제

1. 컴파일 시점에서 오류를 확인할 수 없다.

기대한 입력과 다른 입력을 받아도 확인할 방법이 없다.

Calendar cal = Calendar.getInstance();

cal.add(Calendar.MONDAY, 1);

2. 월 계산

1월을 0으로 표현하는 문제 + Calendar.OCTOBER로 월을 지정하지만 실질적인 값은 9(!=10)인 문제

Calendar 클래스의 상수값

/**
 * Value of the {@link #MONTH} field indicating the
 * first month of the year in the Gregorian and Julian calendars.
 */
public final static int JANUARY = 0;

/**
 * Value of the {@link #MONTH} field indicating the
 * second month of the year in the Gregorian and Julian calendars.
 */
public final static int FEBRUARY = 1;

/**
 * Value of the {@link #MONTH} field indicating the
 * third month of the year in the Gregorian and Julian calendars.
 */
public final static int MARCH = 2;

3. 불변이 아니다.

Date, Calendar객체가 다른 코드에서도 공유하여 사용한다면 한 쪽에서 변경한 날짜값이 다른 부분에 영향을 줄 수 있다.

4. 상수 필드 남용

calendar.add(Calendar.SECOND, 2);

5. 일관성 없는 요일 상수

어디서는 일요일이 0, 어디서는 일요일이 1

6. Date와 Calendar 객체의 역할 분담

다소 치명적인데 년/월/일 계산은 Date 클래스만으로는 부족해서 왔다갔다 하는 문제가 있다. 또한 Calendar객체를 생성하고 Date 객체를 생성하는 프로세스를 거치기 때문에 번거롭고 생성비용이 비싸다.

7. 기타 java.util.Date 하위 클래스의 문제

문제가 있는 클래스를 상속한 하위 클래스 java.sql클래스 TimeStamp equals 메서드 재정의를 위반함.

대안

기존의 개발자들도 자바에서 제공하는 API를 사용하지 않고 적절하게 만든 오픈 소스 라이브러리인 joda time을 사용하였음.

그리고 JDK 8부터 제공된 ZonedDateTime, LocalDate, LocalTime, LocalDateTime

LocalDate

년, 월, 일 정보만 가짐

LocalTime

시, 분, 초 정보만을 가짐

LocalDateTime

LocalDate, LocalTime 정보를 가짐

ZonedDateTime

타임존 또는 시차 개념을 가지고 있는 클래스

Instant

시간을 타임스탬프로 다루기 위해 사용

Example

// 오늘 날짜, 2018-12-11
LocalDate nowDate = LocalDate.now();

// 2018년 12월 11일, 2018-12-11
LocalDate ofDate = LocalDate.of(2018, 12, 11);

// 바로 지금, 2018-12-11T13:12:11
LocalDateTime nowDateTime = LocalDateTime.now();

// 2018년 12월 11일 15시 23분 32초, 2018-12-11T15:23:32
LocalDateTime ofDateTime = LocalDateTime.of(2018, 12, 11, 15, 23, 32);

// Now in LA is 2017-12-10T09:15:12.793-08:00[America/Los_Angeles]
ZonedDateTime nowLa = ZonedDateTime.now();
System.out.println("Now in LA is " + nowLa); 

// Now in Seoul is 2017-12-11T02:15:12.862+09:00[Asia/Seoul]
ZonedDateTime nowSeoul = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
System.out.println("Now in Seoul is " + nowSeoul);

// World Cup is 2002-06-18T20:30+09:00[Asia/Seoul]
ZonedDateTime worldCup = ZonedDateTime.of(2002, 6, 18, 20, 30, 0, 0, ZoneId.of("Asia/Seoul"));
System.out.println("World Cup is " + worldCup);

// Current Instant = 2017-12-22T08:30:18.870Z
Instant current = Instant.now();
System.out.println("Current Instant = "+ current);

// Current Timestamp in seconds = 1513931481
long epochSecond = current.getEpochSecond();
System.out.println("Current Timestamp in seconds = " + epochSecond);

// Current Timestamp in milli seconds = 1513931418870
long epochMilli = current.toEpochMilli();
System.out.println("Current Timestamp in milli seconds = " + epochMilli);

DB에서의 date, timestamp

DATE

  • yyyy-mm-dd

DATETIME

  • yyyy-mm-dd hh:mm:ss
  • ‘1000-01-01 00:00:00’ to ‘9999-12-31 23:59:59’
  • 문자형으로 저장
  • 8byte
  • 수정 시 날짜 시간 직접 입력
  • 글 등록 예약 날짜

TIMESTAMP

  • yyyy-mm-dd hh:mm:ss
  • ‘1970-01-01 00:00:01’ to ‘2038-01-19 03:14:07’ (UTC : 국제 표준 시)
  • 숫자형으로 저장
  • 4byte
  • current_timestamp 사용시 자동으로 입력
  • 자동으로 수정날짜를 저장할 수 있다.

참고 문서

https://madplay.github.io/post/reasons-why-javas-date-and-calendar-was-bad

https://madplay.github.io/post/java8-date-and-time

https://d2.naver.com/helloworld/645609

https://www.daleseo.com/java8-zoned-date-time/

https://www.daleseo.com/java8-instant/