본문 바로가기
프로젝트/텀블벅 클론 코딩

[Java] Java.util.Date 객체 사용 시 문제점

by zangsu_ 2023. 5. 29.

문제 상황

분명 나는 java.util.Date를 사용해서 2023년 3월 5일의 날짜를 생성하는데, 어느 시점에 가서는 이 날짜가 3000년대의 특정 년도로 값이 바뀌어 있는 경험을 몇 번 했다. 이 문제를 조금 더 집중 해 보기로 했다.

아래는 내가 실행한 코드와, 서버에서 확인한 MySQL 로그의 일부이다.

 

실행 한 코드의 일부

Project project = new Project();
//..//
project.setStartDate(new Date(2023, 2, 5));
project.setEndDate(new Date(2032, 3, 5));
//..//
projectRepository.save(project);

 

MySQL 로그의 일부

 

 541 Query
 insert into PROJECT
 (..., END_DATE, ..., START_DATE, ...)
 values
 (..., '3932-04-05 00:00:00', ..., '3923-03-05 00:00:00', ...)

 

실험

가장 먼저 java.util.Date의 작동을 조금 더 확인 해 보기로 했다.

import java.util.Date;

public class DateTest {
    public static void main(String[] args) {
        Date date = new Date(2017, 8, 21);

        System.out.println(date);
        System.out.println("date.getYear() = " + date.getYear());
    }
}

결과는 다음과 같다.

Fri Sep 21 00:00:00 KST 3917
date.getYear() = 2017

보는 바와 같이, Date 변수에서 연도가 저장될 때, 현재 연도보다 1900이 더해진 값이 저장되는 것을 볼 수 있다.

 

Date 클래스 분석

아래는 java.util.Date의 생성자 구현부이다.

/*
Allocates a Date object and initializes it so that it represents midnight, local time, at the 
beginning of the day specified by the year, month, and date arguments.
Deprecated
As of JDK version 1.1, replaced by Calendar.set(year + 1900, month, date) or 
GregorianCalendar(year + 1900, month, date).
Params:
year – the year minus 1900.
month – the month between 0-11.
date – the day of the month between 1-31.
See Also:
Calendar
*/
@Deprecated
public Date(int year, int month, int date) {
    this(year, month, date, 0, 0, 0);
}

@Deprecated
public Date(int year, int month, int date, int hrs, int min, int sec) {
    int y = year + 1900;
	// ... //
}

 

보는 바와 같이, Date 생성자를 사용하기 위한 매개 변수 중 year 변수는 기존 연도에서 1900을 뺀 값을, month 변수는 0~11의 수 중 하나를 전달받는다고 설명하고 있다.

조금 더 찾아 본 결과, Date 클래스는 특정 시점에 대한 정보를 밀리초로 나타내기 위한 클래스이며, 그 기준이 되는 연도가 1900년 이라고 설명한다.

JavaDocs - java.util.Date

 

Date (Java Platform SE 6)

static long UTC(int year, int month, int date, int hrs, int min, int sec)           Deprecated. As of JDK version 1.1, replaced by Calendar.set(year + 1900, month, date, hrs, min, sec) or GregorianCalendar(year + 1900, month, date, hrs, m

docs.oracle.com

또, 1900년을 기준으로 사용하는 이유에 대해서는 1900년도에 연도를 두 자리로 표현하여 편리함을 추구하기 위함이었다고 설명한다. (Java doc의 공식적인 설명은 아닌 만큼, 호기심의 충족을 위한 참고 정도로만 활용하면 좋을 듯 하다.)

SOF 답변

 

Why does java.util.Date represent Year as "year-1900"?

In java.util.Date: * In all methods of class <code>Date</code> that accept or return * year, month, date, hours, minutes, and seconds values, the * following representations are use...

stackoverflow.com

 

즉, java.util.Date를 사용해 2019년 11월 26일을 저장하기 위해선 Date(119, 10, 26)와 같은 방식으로 사용해야 하는 것이다.

추가적으로, 구현부에 포함되어 있는 @Deprecated를 확인하면 알 수 있듯, 이제는 사용을 권장하지 않는 클래스임을 볼 수 있다. 현재는 Callendar 클래스의 사용을 권장하고 있다.

정리

java.util.Date는 정확한 날짜 저장을 위한 클래스가 아닌, 특정 시점에 대한 정보를 밀리초로 저장하기 위한 클래스이다. 물론 시간 정보를 저장하는 만큼 오늘의 날짜를 얻을 수 있지만, 애초에 목적이 다른 만큼 나와 같은 문제는 얼마든지 발생할 수 있을 것 같다. 프로젝트는 java.util.Calendar로 리팩토링을 진행할 예정이다.

 

추가적으로, 이 이유 이외에도 불변객체가 아닌 것을 포함해 여러 이유로 java.util.Date를 권장하지 않는데 관심있는 사람은 더 찾아보면 좋을 듯 하다.

댓글