개발/Java

java.util.Date

함수형 인간 2025. 3. 14. 07:03

java.util.Date는 Java 초기부터 제공된 날짜와 시간을 표현하는 클래스.

하지만 여러 문제점과 부족한 기능으로 인해 Java 8부터는 java.time 패키지의 클래스들(LocalDate, LocalDateTime, ZonedDateTime 등)을 사용하는 것이 권장됨. 

java.util.Date의 특징:

  • 날짜와 시간 표현: java.util.Date는 특정 시점의 날짜와 시간을 나타낸다. 내부적으로는 1970년 1월 1일 00:00:00 GMT(그리니치 표준시)부터 경과한 밀리초(milliseconds)를 long 값으로 저장한다.
  • 가변성 (Mutable): java.util.Date 객체는 가변(mutable). 즉, setDate(), setMonth(), setYear() 등의 메서드를 사용하여 객체의 값을 변경할 수 있다. 이 때문에 멀티스레드 환경에서 예상치 못한 문제가 발생할 수 있다.
  • 타임존: java.util.Date 자체는 타임존 정보를 가지고 있지 않는다. 하지만 toString() 메서드를 호출하면 시스템의 기본 타임존을 사용하여 날짜와 시간을 문자열로 변환. 이 때문에 타임존 관련 혼란이 발생할 수 있다.
  • 월(Month)의 시작: java.util.Date에서 월(Month)은 0부터 시작합니다 (0: 1월, 1: 2월, ..., 11: 12월). 이는 직관적이지 않아서 실수를 유발할 수 있다.
  • 메서드의 Deprecation: 많은 메서드들이 Deprecated (사용 중단됨) 상태. getYear(), getMonth(), getDate(), getHours(), getMinutes(), getSeconds() 등 대부분의 getter/setter 메서드들이 Deprecated 되었고, 대신 Calendar 클래스를 사용하도록 권장.
  • Calendar 와의 관계: java.util.Date는 java.util.Calendar 객체로 변환하거나 Calendar 객체로부터 Date객체를 생성하는 것이 가능.

java.util.Date의 주요 메서드 (Deprecated 되지 않은 것들):

  • Date(): 현재 날짜와 시간으로 초기화된 Date 객체를 생성.
  • Date(long date): 1970년 1월 1일 00:00:00 GMT로부터 주어진 밀리초만큼 경과한 시점으로 초기화된 Date 객체를 생성.
  • getTime(): 1970년 1월 1일 00:00:00 GMT로부터 이 Date 객체가 나타내는 시점까지의 밀리초를 반환.
  • setTime(long time): 이 Date 객체를 1970년 1월 1일 00:00:00 GMT로부터 주어진 밀리초만큼 경과한 시점으로 설정.
  • before(Date when): 이 Date 객체가 주어진 Date 객체보다 이전 시점인지 확인.
  • after(Date when): 이 Date 객체가 주어진 Date 객체보다 이후 시점인지 확인.
  • equals(Object obj): 이 Date 객체와 주어진 객체가 같은 시점을 나타내는지 비교.
  • compareTo(Date anotherDate): 이 Date 객체를 주어진 Date 객체와 비교하여 순서를 정함. (이전이면 음수, 같으면 0, 이후면 양수)
  • toString(): 이 Date 객체를 문자열로 변환. 시스템의 기본 타임존을 사용. (예: "Tue Oct 29 15:30:00 KST 2024")
  • clone(): 이 Date 객체의 복사본을 반환.
  • from(Instant instant) (Java 8 이상): java.time.Instant 객체로부터 java.util.Date 객체를 생성.
  • toInstant() (Java 8 이상): 이 Date 객체를 java.time.Instant 객체로 변환.

java.util.Date 사용 예시:

Java
 
import java.util.Date;
import java.text.SimpleDateFormat;

public class DateExample {
    public static void main(String[] args) {
        // 현재 날짜와 시간으로 Date 객체 생성
        Date now = new Date();
        System.out.println("Current Date: " + now); // 시스템 기본 타임존으로 출력

        // 1970년 1월 1일 00:00:00 GMT로부터 1000 밀리초 경과한 시점
        Date past = new Date(1000);
        System.out.println("Past Date: " + past);

        // 특정 날짜/시간으로 Date 객체 생성 (SimpleDateFormat 사용)
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date specificDate = sdf.parse("2023-12-25 10:30:00");
            System.out.println("Specific Date: " + specificDate);
        } catch (java.text.ParseException e) {
            System.out.println("Date parsing error: " + e.getMessage());
        }

        // 날짜 비교
        Date date1 = new Date();
        Date date2 = new Date(date1.getTime() + 1000 * 60 * 60); // 1시간 후

        System.out.println("date1.before(date2): " + date1.before(date2)); // true
        System.out.println("date1.after(date2): " + date1.after(date2));   // false
        System.out.println("date1.equals(date2): " + date1.equals(date2)); // false

        // java.time.Instant로 변환 (Java 8 이상)
        java.time.Instant instant = now.toInstant();
        System.out.println("Instant: " + instant);

        // java.time.Instant에서 Date로 변환 (Java 8 이상)
         Date fromInstant = Date.from(instant);
         System.out.println("From Instant: " + fromInstant);
    }
}

SimpleDateFormat을 사용한 날짜/시간 포매팅:

java.util.Date 객체를 원하는 형식의 문자열로 표현하거나, 문자열을 java.util.Date 객체로 파싱하려면 java.text.SimpleDateFormat 클래스를 사용.

Java
 
import java.util.Date;
import java.text.SimpleDateFormat;

public class DateFormatExample {
    public static void main(String[] args) {
        Date now = new Date();

        // 다양한 형식으로 Date를 문자열로 변환
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdf2 = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
        SimpleDateFormat sdf3 = new SimpleDateFormat("E, MMM dd, yyyy"); // 요일, 월, 일, 년

        System.out.println("Format 1: " + sdf1.format(now));
        System.out.println("Format 2: " + sdf2.format(now));
        System.out.println("Format 3: " + sdf3.format(now));

        // 문자열을 Date로 파싱
        String dateString = "2023-11-15";
        SimpleDateFormat sdf4 = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date parsedDate = sdf4.parse(dateString);
            System.out.println("Parsed Date: " + parsedDate);
        } catch (java.text.ParseException e) {
            System.out.println("Parsing error: " + e.getMessage());
        }
    }
}

SimpleDateFormat의 주요 패턴 문자:

  • yyyy: 년 (4자리)
  • yy: 년 (2자리)
  • MM: 월 (2자리, 01-12)
  • M: 월 (1자리 또는 2자리, 1-12)
  • dd: 일 (2자리, 01-31)
  • d: 일 (1자리 또는 2자리, 1-31)
  • HH: 시 (24시간 형식, 00-23)
  • H: 시 (24시간 형식, 0-23)
  • hh: 시 (12시간 형식, 01-12)
  • h: 시 (12시간 형식, 1-12)
  • mm: 분 (00-59)
  • ss: 초 (00-59)
  • SSS: 밀리초 (000-999)
  • E: 요일 (짧은 형식, 예: "월")
  • EEEE: 요일 (긴 형식, 예: "월요일")
  • a: 오전/오후 (AM/PM)
  • z: Time zone name
  • Z: Time zone offset

주의사항 및 권장 사항:

  • 가변성: java.util.Date는 가변 객체이므로, 멀티스레드 환경에서 사용할 때는 주의해야 한다. 여러 스레드에서 동시에 Date 객체를 변경하면 예기치 않은 결과가 발생할 수 있다. 가능하면 불변(immutable) 객체인 java.time 패키지의 클래스들을 사용하는 것이 좋다.
  • 타임존: java.util.Date 자체는 타임존 정보를 갖지 않지만, toString() 메서드나 SimpleDateFormat을 사용할 때 시스템의 기본 타임존이 사용된다. 타임존을 명확하게 처리해야 하는 경우에는 java.util.Calendar나 java.time.ZonedDateTime을 사용하는 것이 좋다.
  • SimpleDateFormat은 스레드 안전하지 않음: SimpleDateFormat 객체는 thread-safe하지 않다. 멀티스레드 환경에서 SimpleDateFormat 객체를 공유하면 문제가 발생할 수 있다. 각 스레드마다 별도의 SimpleDateFormat 객체를 생성하거나, ThreadLocal을 사용하거나, Java 8 이상의 java.time.format.DateTimeFormatter를 사용하는 것이 좋다.
  • Java 8 이상에서는 java.time 패키지 사용: 가능하면 java.util.Date 대신 java.time 패키지의 클래스들(LocalDate, LocalDateTime, ZonedDateTime, Instant 등)을 사용하는 것이 좋다. java.time 패키지는 불변 객체, 명확한 타임존 처리, 풍부한 기능 등 여러 장점을 제공.