Java - Time 패키지

제훈·2024년 7월 19일

Java

목록 보기
19/34

기본적으로 사용했던 날짜, 시간을 다루는 API -> java.util.Datejava.util.Calendar
하지만 Date, Calendar는 불편해서 JDK 8에서 개선된 날짜와 시간 API java.time 패키지를 제공한다.


Date 와 Calendar 클래스

Date 클래스는 JDK 1.0 부터 날짜를 가볍게 취급하기 위해 사용되던 클래스
지금은 생성자를 비롯해 대부분의 메소드가 Deprecated -> 사용 권장 X

Calendar 클래스는 JDK 1.1 부터 새롭게 제공되는 시간과 날짜에 관한 처리를 담당하는 클래스
Calendar 클래스가 추가되면서 Date의 많은 메소드는 Deprecated 되었다.

Date 클래스보다는 많은 보완이 됐지만 여전한 단점들이 있다.

  1. Calendar 인스턴스는 불변객체가 아니기 때문에 값을 수정할 수 있다.
    • set 메소드를 통해 값을 변경할 수 있기 때문에 어느 흐름에 중간에 값이 바뀐다고 하면 알아채기가 힘들고 사이드 이팩트가 발생할 가능성이 높다. 또한 멀티 스레드 환경에서도 안전하지 않다.
  2. 윤초(leap second)를 고려하지 않는다.
    • 윤초란?
      협정 세계시에서 사용하는 세슘 원자 시계와 실제 지구의 자전/공전 속도를 기준으로 한 태양시의 차이로 인해 발생한 오차를 보정하기 위해 추가하는 1초이다. 12월 31일의 마지막에 추가하거나, 혹은 6월 30일의 마지막에 추가한다. 윤초는 사소해 보이지만 실제 2012년 링크드인 과 같은 대규모 서비스의 서버를 마비시킨 버그를 발생한 적도 있다.
  3. Calendar 클래스는 월을 나타낼 때 0 부터 11까지로 표현하는 불편함이 있다.
    • 하지만 일주일을 나타내는 숫자는 1부터 시작이다. 즉, 일관성이 부족하다.

Date 다뤄보기

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

public class Application1 {
    public static void main(String[] args) {
        Date date = new Date();         // 시스템의 현재 시간을 가진 객체 생성
        System.out.println(date);

        System.out.println("long 타입 시간 : " + date.getTime());   // KST 기준으로 1970/1/1 오전 9시 이후 흐른 시간(milliseconds)
        System.out.println("long 타입 시간을 활용한 Date : " + new java.util.Date(0L));
        System.out.println("현재 시간을 활용한| Date : " + new java.util.Date(date.getTime()));

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 날짜 출력 형식을 문자열로 만들기
        // SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");

        String todayFormat = sdf.format(date);
        System.out.println(todayFormat);
    }
}

sdf 에 날짜 포맷에 "yyyy-MM-dd HH:mm:ss E요일"을 하면 요일도 추가된다.


Calendar 다뤄보기

Date 형 대비 개선점
1. timezone과 관련된 기능이 추가됐다.
2. 윤년 관련 기능이 내부적으로 추가됐다.
3. 날짜 및 시간 필드 개념을 추가해 불필요한 메소드명을 줄였다.

import java.util.Calendar;
import java.util.GregorianCalendar;

public class Application2 {
    public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();     // new 연산자 사용 불가. 생성자가 protected로 막혀 있기 때문
        System.out.println("calendar = " + calendar);
        // Month와 같은 것들을 잘 보면인덱스형태로 되어 있는 것을 알 수 있다.

        Calendar calendar2 = new GregorianCalendar();
        System.out.println(calendar2.get(Calendar.YEAR));

        int year = 2000;
        int month = 1 - 1; // 1월
        int day = 3;
        int hour = 3;
        int minute = 31;
        int second = 28;

        Calendar birthday = new GregorianCalendar(year, month, day, hour, minute, second);
        System.out.println(birthday);

        System.out.print(birthday.get(Calendar.YEAR) + " ");
        System.out.print((birthday.get(Calendar.MONTH) + 1) + " ");
        System.out.print(birthday.get(Calendar.DAY_OF_MONTH) + " ");
        System.out.print(birthday.get(Calendar.HOUR_OF_DAY) + " ");
        System.out.print(birthday.get(Calendar.MINUTE) + " ");
        System.out.print(birthday.get(Calendar.SECOND) + " ");
        System.out.print(birthday.get(Calendar.MILLISECOND) + " ");

        String weekDay = "";
        int dayNum = birthday.get(Calendar.DAY_OF_WEEK);
        switch (dayNum) {
            case 1: weekDay = "일"; break;
            case 2: weekDay = "월"; break;
            case 3: weekDay = "화"; break;
            case 4: weekDay = "수"; break;
            case 5: weekDay = "목"; break;
            case 6: weekDay = "금"; break;
            case 7: weekDay = "토"; break;
        }
        System.out.println("내가 태어난 요일은 " + weekDay +"요일");

        System.out.println("AM/PM " + birthday.get(Calendar.AM_PM));
        System.out.println("hourOfDay " + birthday.get(Calendar.HOUR_OF_DAY));
        System.out.println("hour = " + birthday.get(Calendar.HOUR));
        System.out.println("minute = " + birthday.get(Calendar.MINUTE));
        System.out.println("second = " + birthday.get(Calendar.SECOND));
    }
}

hourOfDay : 24시간 체계
hour : 12시간 체계


Time 패키지

간단하게 Date, Calendar 패키지를 알아봤으니

JDK 1.8 버전에 추가된 Time 패키지는 기존의 시간을 다뤘던 것들의 단점을 해소하기 위해 탄생됐다.

Time 하위 패키지

패키지설명
java.time날짜와 시간 관련 클래스들을 제공한다
java.time.chronoISO-8601 에 정의된 외에 달력 시스템을 위한 클래스들을 제공한다
java.time.format날짜와 시간 파싱과 형식화 관련 클래스들을 제공한다
java.time.temporal날짜와 시간의 필드와 단위 관련 클래스들을 제공한다
java.time.zone시간대 관련된 클래스들을 제공한다

핵심 클래스

클래스명설명
LocalTime시간 관련 작업할 때 사용하는 클래스. LocalTime 객체는 두 개의 정적 메소드를 통해 반환 받을 수 있다.
LocalDate날짜 관련 작업할 때 사용하는 클래스. LocalDate 객체도 두 개의 정적 메소드로 반환 받는다.
LocalDateTime시간과 날짜를 함께 작업해야할 때 사용하는 클래스
ZonedDateTime시간대(Time Zone) 을 활용한 작업해야할 때 사용하는 클래스
import java.time.*;

public class Application1 {
    public static void main(String[] args) {
        LocalTime timeNow = LocalTime.now();
        LocalTime timeNow2 = LocalTime.of(18, 30, 20);
        System.out.println("time = " + timeNow);
        System.out.println("time2 = " + timeNow2);

        LocalDate dateNow = LocalDate.now();
        LocalDate dateOf = LocalDate.of(2024, 7, 19);
        System.out.println("dateNow = " + dateNow);
        System.out.println("dateOf = " + dateOf);

        LocalDateTime dateTimeNow = LocalDateTime.now();
        LocalDateTime dateTimeOf = LocalDateTime.of(dateNow, timeNow);
        System.out.println("dateTimeNow = " + dateTimeNow);
        System.out.println("dateTimeOf = " + dateTimeOf);

        ZonedDateTime zonedDateTimeNow = ZonedDateTime.now();
        ZonedDateTime zonedDateTimeOf = ZonedDateTime.of(dateOf, timeNow2, ZoneId.of("Asia/Seoul"));
        System.out.println("dateTimeNow = " + zonedDateTimeNow);
        System.out.println("zonedDateTimeOf = " + zonedDateTimeOf);

    }
}

필드값 확인하기

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZonedDateTime;

public class Application2 {
    public static void main(String[] args) {

        /* 수업목표. time 패키지의 클래스들이 가지고 있는 필드값을 확인할 수 있다. */
        LocalTime localTime = LocalTime.now();

        System.out.println("localTime = " + localTime);
        System.out.println("시간 : " + localTime.getHour());
        System.out.println("분 : " + localTime.getMinute());
        System.out.println("초 : " + localTime.getSecond());
        System.out.println("나노초 : " + localTime.getNano());

        LocalDate localDate = LocalDate.now();
        System.out.println("localDate = " + localDate);
        System.out.println("년 : " + localDate.getYear());
        System.out.println("월 : " + localDate.getMonth());
        System.out.println("월 숫자 : " + localDate.getMonthValue());
        System.out.println("월 중에 몇 번째 일 : " + localDate.getDayOfMonth());
        System.out.println("1년 중에 몇 번째 일 : " + localDate.getDayOfYear());
        System.out.println("한 주의 몇 번째 일 : " + localDate.getDayOfWeek());

        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        System.out.println("zonedDateTime = " + zonedDateTime);
        System.out.println("zone 정보 : " + zonedDateTime.getZone());
        System.out.println("시자 : " + zonedDateTime.getOffset());

    }
}


클래스 활용한 덧셈, 뺄셈, 불변 특성 알아보기

객체를 변화시킬 수 없어서 (불변이어서) 매번 새로운 객체를 생성한다.

import java.time.LocalDateTime;

public class Application3 {
    public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println("현재 시간 = " + localDateTime);
        System.out.println("주소 값 = " + System.identityHashCode(localDateTime));

        LocalDateTime localDateTime2 = localDateTime.plusMinutes(30);
        System.out.println("30분 후 = " + localDateTime2);
        System.out.println("주소 값 = " + System.identityHashCode(localDateTime2));

        LocalDateTime localDateTime3 = localDateTime.minusHours(3);
        System.out.println("3시간 전 = " + localDateTime3);
        System.out.println("주소 값 = " + System.identityHashCode(localDateTime3));
    }
}

주소가 다 다른다는건 객체가 매번 생성됐다는 뜻이다.


날짜 비교 연산 메소드

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;

public class Application4 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        LocalDateTime localDateTime = LocalDateTime.now();
        ZonedDateTime zonedDateTime = ZonedDateTime.now();

        LocalDate past = LocalDate.of(2022, 11, 11);
        LocalDateTime future = LocalDateTime.of(2025, 1, 3, 15, 20, 30);
        ZonedDateTime now = ZonedDateTime.now();

        System.out.println(localDate.isAfter(past));
        System.out.println(localDateTime.isBefore(future));
        System.out.println(zonedDateTime.isEqual(now));
    }
}

isAfter(날짜) : 날짜보다 이후인지 boolean 값 반환
isBefore(날짜) : 날짜보다 이전인지 boolean 값 반환
isEqual(날짜) : 날짜와 같은 시간인지 boolean 값 반환

isEqual() 로 비교하는건 time 패키지 자료형마다 전달인자가 같은 타입이어야 True를 반환할 수 있다.


시간 패턴 parser, 문자열 변환

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class Application5 {
    public static void main(String[] args) {
        String timeNow = "14:05:10";
        String dateNow = "2022-10-12";

        LocalTime localTime = LocalTime.parse(timeNow);
        LocalDate localDate = LocalDate.parse(dateNow);
        LocalDateTime localDateTime = LocalDateTime.parse(localDate + "T" + localTime);

        System.out.println("localTime = " + localTime);
        System.out.println("localDate = " + localDate);
        System.out.println("localDateTime = " + localDateTime);

        /* 패턴 인식해줘야할 때 */
        String timeNow2 = "14-05-10";
        String dateNow2 = "221012";

        LocalTime localTime2 = LocalTime.parse(timeNow2, DateTimeFormatter.ofPattern("HH-mm-ss"));
        LocalDate localDate2 = LocalDate.parse(dateNow2, DateTimeFormatter.ofPattern("yyMMdd"));

        System.out.println("localTime2 = " + localTime2);
        System.out.println("localDate2 = " + localDate2);

        /* 설명. time 패키지가 인식한 날자 및 시간을 원하는 문자열로 반환하기 */
        String dateFormat = localDate2.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String timeFormat = localTime2.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
        
        System.out.println("dateFormat = " + dateFormat);
        System.out.println("timeFormat = " + timeFormat);
    }
}

profile
백엔드 개발자 꿈나무

0개의 댓글