티스토리 뷰

Java & Kotlin

JAVA8 java.time 훑어보기 - (1)

터프남 2021. 3. 25. 13:52
728x90

java8 이전부터 사용된 Date 객체와 Calendar를 사용하지 말아야 할 이유 (직관적이지 않고 불변이 아닌 가변..)는 찾아보고

이미 java8이 나온지 엄청 지났고 여러 블로그에 정리가 잘 되어있지만  나도 java8부터 추가된 java.time 패키지에 추가된 클래스를 살펴보기로 함.

java.time 패키지

날짜와 시간 객체에는 크게 5가지가 있다.

 

LocalDate - 날짜 정보만 제공

LocalTime - 시간 정보만 제공

LocalDateTime - 날짜와 시간 정보를 모두 제공

ZonedDateTime - 특정 타임존(TimeZone)의 날짜와 시간을 제공

Instant - 특정 시점의 Time-Stamp

그리고 이러한 클래스들은 모두 불변 객체이고 Thread-safe 하다.

LocalDate

로컬 날짜 클래스로 날짜 정보만을 저장하고 가져올 수 있다.

LocalDate nowDate = LocalDate.now();
LocalDate targetDate = LocalDate.of(int year, int month, int dayOfMonth);

참고로 새로 추가되는 자바 API의 불변 객체 생성은 대부분이 of()로 시작된다. List.of(...) 이런 식으로

private static void printAllLocalDate() {
    LocalDate nowDate = LocalDate.now();
    LocalDate targetDate = LocalDate.of(2021, 3, 1);

    System.out.println("현재날짜 가져오기 = " + nowDate);
    System.out.println("targetDate = " + targetDate);

    System.out.println("현재월의 날짜를 얻어옴: " + targetDate.getDayOfMonth());
    System.out.println("년도를 가져옴: " + targetDate.getYear());
    System.out.println("월을 숫자로 받아옴: " + targetDate.getMonthValue());
    System.out.println("월을 가져옴 (Month 열거값): " + targetDate.getMonth());
    System.out.println("일자를 가져옴 (DayOfWeek 열거값): " + targetDate.getDayOfWeek());
    System.out.println("일년의 몇 번째 일?: " + targetDate.getDayOfYear());
    System.out.println("윤년여부: "+ targetDate.isLeapYear());  //2021년은 윤년이 아니다.

    System.out.println("년도 더하기: " + targetDate.plusYears(1));
    System.out.println("월 더하기: " + targetDate.plusMonths(1));
    System.out.println("주 더하기: " + targetDate.plusWeeks(1));
    System.out.println("일 더하기: " + targetDate.plusDays(1));

}

//결과
현재날짜 가져오기 = 2021-03-25
targetDate = 2021-03-01
현재월의 날짜를 얻어옴: 1
년도를 가져옴: 2021
월을 숫자로 받아옴: 3
월을 가져옴 (Month 열거값): MARCH
일자를 가져옴 (DayOfWeek 열거값): MONDAY
일년의 몇 번째 일?: 60
윤년여부: false
년도 더하기: 2022-03-01
월 더하기: 2021-04-01
주 더하기: 2021-03-08
일 더하기: 2021-03-02

LocalTime

로컬 시간 클래스로 시간 정보만을 저장하고 가져올 수 있다.

LocalTime nowTime = LocalTime.now();
LocalTime.of(int hour, int minute, int second, int nanoOfSecond)

예제 코드

private static void printAllLocalTime() {
    LocalTime nowTime = LocalTime.now();
    LocalTime targetTime = LocalTime.of(12, 35, 33,9999);

    System.out.println("현재시간 가져오기: " + nowTime);
    System.out.println("targetTime = " + targetTime);

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

    System.out.println("시간 더하기: " + targetTime.plusHours(1));
    System.out.println("분 더하기: " + targetTime.plusMinutes(1));
    System.out.println("초 더하기: " + targetTime.plusSeconds(1));
    System.out.println("나노 초 더하기: " + targetTime.plusNanos(1));

    System.out.println("시간 빼기: " + targetTime.minusHours(1));
    System.out.println("분 빼기: " + targetTime.minusMinutes(1));
    System.out.println("초 빼기: " + targetTime.minusSeconds(1));
    System.out.println("나노 초 빼기: " + targetTime.minusNanos(1));

}
//결과
현재시간 가져오기: 11:31:31.481466
targetTime = 12:35:33.000009999
시간: 12
분: 35
초: 33
나노초: 9999
시간 더하기: 13:35:33.000009999
분 더하기: 12:36:33.000009999
초 더하기: 12:35:34.000009999
나노 초 더하기: 12:35:33.000010
시간 빼기: 11:35:33.000009999
분 빼기: 12:34:33.000009999
초 빼기: 12:35:32.000009999
나노 초 빼기: 12:35:33.000009998

LocalDateTime

클래스명에서 알 수가 있듯이 LocalDate와 LocalTime을 모두 필요로 할 때 사용하는 클래스이다.

날짜와 시간정보가 모두 필요할 때 사용하면 된다. LocalDate와 LocalTime을 합친 클래스라고 생각하면 된다.

LocalDateTime currentDateTime = LocalDateTime.now();
LocalDateTime targetDateTime = LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond);

예제 코드는 따로 없다. 왜냐하면 LocalDate와 LocalTime에서 제공하는 메서드는 모두 제공하기 때문이다.

private static void printAllLocalDateTime() {

    //LocalDate와 LocalTime을 합친 LocalDateTime이 있다.
    //날짜와 시간정보가 모두 필요할때 사용한다.
    LocalDateTime nowLocalDateTime = LocalDateTime.now();
    LocalDateTime targetLocalDateTime = LocalDateTime.of(2021, 3, 1, 12, 35);

    System.out.println("nowLocalDateTime = " + nowLocalDateTime);
    System.out.println("기존 LocalDate와 LocalTime이 제공하는 메서드를 모두 사용할 수 있다.");

}

그런데 LocalDateTime을 LocalDate 또는 LocalTime으로 변환하려면 아래와 같이 사용하면 된다.

LocalDateTime nowLocalDateTime = LocalDateTime.now();
LocalDateTime targetLocalDateTime = LocalDateTime.of(2021, 3, 1, 12, 35);

//LocalDateTime을 LocalDate 또는 LocalTime으로 변환 하는 방법
LocalDate localDate = targetLocalDateTime.toLocalDate();
LocalTime localTime = targetLocalDateTime.toLocalTime();

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

//결과
localDate = 2021-03-01
localTime = 12:35

ZonedDateTime

ISO-8601 달력 시스템에서 정의하고 있는 타임존(time-zone)의 날짜와 시간을 저장하는 클래스이다.

표준 시간이 같은 지역을 묶어서 시간대 규칙 집합을 정의한다. ZoneRules 클래스에는 약 40개 정도의 시간대가 있다.

다음처럼 지역 ID로 특정 ZoneID를 구분한다.

한 마디로 날짜와 시간 정보를 포함하고 그 지역의 시간대를 추가한 것이 ZonedDateTime 이다.

ZoneId seoulZone = ZoneId.of("Asia/Seoul");
ZonedDateTime SeoulDateTime = ZonedDateTime.now(seoulZone);

출력 시에는 맨 뒤에 타임존에 대한 정보가 추가적으로 붙는다. 

출처 - 모던자바인액션 ZonedDataTime의 개념

특정 지역의 시간대를 알고 싶을 때 사용할 수 있다.

지역 ID는 '{지역}/{도시}' 형식으로 이루어진다. 

ZoneId의 새로운 메서드인 toZoneId로 기존의 TimeZone 객체를 ZoneId 객체로 변환할 수 있다.

ZoneId zoneId = TimeZone.getDefault().toZoneId();
System.out.println(zoneId); //Asia/Seoul

ZoneId 객체를 얻은 다음 LocalDate, LocalDateTime, Instatnt를 이용해서 ZonedDataTime 인스턴스로 변환할 수 있다.

ZoneId romeZone = ZoneId . of ("Europe/Rome");
LocalDate date = LocalDate.of(2014, Month.MARCH, 18);
ZonedDateTime zdt1 = date.atStartOfDay(romeZone);
LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);
ZonedDateTime zdt2 = dateTime.atZone(romeZone);
Instant instant = Instant.now();
ZonedDateTime zdt3 = instant.atZone(romeZone);

System.out.println("zdt1 = " + zdt1);
System.out.println("zdt2 = " + zdt2);
System.out.println("zdt3 = " + zdt3);

//결과
zdt1 = 2014-03-18T00:00+01:00[Europe/Rome]
zdt2 = 2014-03-18T13:45+01:00[Europe/Rome]
zdt3 = 2021-03-25T05:30:40.658385+01:00[Europe/Rome]

Instant 클래스

사람은 보통 주, 날짜, 시간, 분으로 날짜와 시간을 계산하지만 기계에서는 이와 같은 단위로 시간을 표현하기 어렵다.

기계의 관점에서는 연속된 시간에서 특정 지점을 하나의 큰 수로 표현하는 것이 가장 자연스러운 시간 표현 방법이다.

Instant 클래스에 서는 이와 같은 기계적인 관점에서 시간을 표현한다.

주로 특정한 두 시점 간의 시간적 우선순위를 따질 때 사용한다.

Instant 클래스는 나노초(10억 분의 1초)의 정밀도를 제공한다.

 

그리고 Instant 클래스는 항상 UTC(협정세계시) 를 기준으로 하기 때문에 LocalTime과는 차이가 있다.

한국의 시간을 알려면 UTC 시간에 +09:00 해보면 된다. 한국 시간은 UTC 시간 기준으로 9시간 이후다.

Instant now = Instant.now();
System.out.println("now = " + now);

코드를 실행해보면 UTC 의 시간이 나오는데 여기서 9시간을 더하면 한국 시간이다.

private static void printAllInstant() {
    Instant instant1 = Instant.now();
    Instant instant2 = Instant.now();

    if (instant1.isBefore(instant2)) {
        System.out.println("instant1이 빠릅니다.");
    } else if (instant1.isAfter(instant2)) {
        System.out.println("instant1이 늦습니다.");
    } else {
        System.out.println("동일한 시간입니다.");
    }
    System.out.println("차이(nanos): " + instant1.until(instant2, ChronoUnit.NANOS));
}

참고

모던자바인액션 www.yes24.com/Product/Goods/77125987?OzSrank=1

이것이 자바다 www.yes24.com/Product/Goods/15651484?OzSrank=2

자바의 정석 www.yes24.com/Product/Goods/24259565?OzSrank=2

728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함