[Java 응용] java.time 패키지 - 2. 단위 및 필드 & Temporal 인터페이스와 날짜 조정

Kyung Jae, Cheong·2024년 8월 30일
0
post-thumbnail

0. java.time 패키지

  • Java의 java.time 패키지는 JDK 8부터 도입된 새로운 날짜와 시간 라이브러리로, 기존의 java.util.Datejava.util.Calendar의 문제점을 해결하기 위해 설계되었습니다.

java.time 패키지 포스팅 목차

  1. java.time 패키지 개요
  2. 주요 클래스 목록 및 용도별 분류
  3. 핵심 인터페이스 & 단위 및 필드
  4. 날짜 및 시간의 파싱과 포맷팅

(현재 포스팅) 2. 핵심 인터페이스 & 단위 및 필드

이번 포스팅에서는 java.time 패키지에서 날짜와 시간을 조작하거나 계산할 때 사용하는 다양한 단위와 필드를 표현하는 클래스들을 먼저 정리해보고, java.time 패키지 클래스들의 공통적인 기능들을 구현하는 Temporal계열의 인터페이스 및 주요 메서드들을 정리해볼 예정입니다.

2. 핵심 인터페이스 & 단위 및 필드

주요 내용

  • 단위 및 필드 클래스
    • ChronoUnitChronoField는 날짜와 시간의 조작에 필수적인 단위와 필드를 정의합니다.
    • 이들은 특정 시간 간격을 계산하거나, 날짜와 시간의 특정 부분을 읽고 설정하는 데 사용됩니다.
    • 각 클래스는 다양한 유틸리티 메서드를 제공하여, 날짜와 시간 작업을 더욱 직관적이고 효율적으로 처리할 수 있도록 도와줍니다.
  • Temporal 계열 인터페이스
    • Temporal 계열 인터페이스는 java.time 패키지에서 날짜와 시간 객체들이 공통적으로 구현하는 기능을 정의합니다. Temporal, TemporalAccessor, TemporalAdjuster, TemporalAmount 등 다양한 인터페이스가 존재하며, 이들은 날짜와 시간의 조작, 계산, 비교 등을 위한 핵심 기능을 제공합니다. 이러한 인터페이스를 이해함으로써, java.time 패키지의 강력한 시간 처리 기능을 효과적으로 활용할 수 있습니다.

2.1. 단위 및 필드 클래스: ChronoUnit과 ChronoField

  • java.time 패키지에는 날짜와 시간을 조작하거나 계산할 때 사용하는 다양한 단위와 필드를 표현하는 클래스가 있습니다. 그 중에서도 ChronoUnitChronoField는 가장 핵심적인 역할을 합니다.

ChronoUnit

  • ChronoUnit 클래스는 시간 단위를 정의하는 Enum으로, 연도, 월, 일, 시간, 분, 초와 같은 다양한 시간 단위를 표현합니다.
    • java.time.temporal 패키지에 열거형으로 TemporalUnit 인터페이스를 구현하며, 날짜 및 시간의 계산, 차이 계산 등에 사용됩니다.
  • 주요 시간 및 날짜 단위
ChronoUnit설명
NANOS나노초
MICROS마이크로초
MILLIS밀리초
SECONDS
MINUTES
HOURS시간
DAYS일 단위
WEEKS주 단위
MONTHS
YEARS연도
DECADES10년
CENTURIES100년
MILLENNIA1000년
ERAS시대(기원전, 서기)
FOREVER무한대
  • 주요 메서드
Method반환타입설명
.getDuration()Duration해당 단위의 길이를 Duration으로 반환합니다.
.isDurationEstimated()boolean해당 단위의 길이가 추정치인지 여부를 반환합니다.
.isDateBased()boolean해당 단위가 날짜 기반인지 여부를 반환합니다.
.isTimeBased()boolean해당 단위가 시간 기반인지 여부를 반환합니다.
.isSupportedBy(Temporal)boolean지정된 Temporal 객체가 해당 단위를 지원하는지 확인합니다.
.addTo(Temporal, long)Temporal해당 단위의 값을 더한 새로운 Temporal 객체를 반환합니다.
.between(Temporal, Temporal)long두 Temporal 객체 사이의 차이를 해당 단위로 계산하여 반환합니다.

예시코드

import java.time.temporal.ChronoUnit;
import java.time.LocalDate;
import java.time.temporal.Temporal;

LocalDate today = LocalDate.now();
LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
System.out.println("Next Year: " + nextYear); // 출력: Next Year: 2025-08-29

long daysBetween = ChronoUnit.DAYS.between(today, nextYear);
System.out.println("Days Between: " + daysBetween); // 출력: Days Between: 365 (윤년이 아닌 경우)

Temporal nextMonth = ChronoUnit.MONTHS.addTo(today, 1);
System.out.println("Next Month: " + nextMonth); // 출력: Next Month: 2024-09-29

ChronoField

  • ChronoField 클래스는 날짜와 시간의 특정 필드를 정의하는 Enum으로, 연도, 월, 일, 시, 분, 초 등과 같은 필드를 표현합니다.

    • java.time.temporal 패키지에 열거형으로 TemporalField 인터페이스를 구현하며, 특정 날짜 또는 시간의 필드를 읽거나 조작할 때 사용됩니다.
    • 각 필드는 getFrom() 메서드를 통해 값을 가져올 수 있으며, with() 메서드를 통해 값을 설정할 수 있습니다. (참고로 Java에서 with는 새로운 불변 객체를 생성한다는 뜻이 있습니다.)
  • 주요 시간 및 날짜 필드

ChronoField설명범위
ERA연대 (BC 혹은 AD)0(BC), 1(AD)
YEAR연도-999,999,999 ~ 999,999,999
MONTH_OF_YEAR연중 월1(Jan) ~ 12(Dec)
DAY_OF_YEAR연중 날짜1 ~ 365(366)
DAY_OF_MONTH월중 날짜1 ~ 28/29/30/31
DAY_OF_WEEK요일1(Mon) ~ 7(Sun)
HOUR_OF_DAY(24시간) 시간0 ~ 23
CLOCK_HOUR_OF_DAY(24시간) 시간1 ~ 24
AMPM_OF_DAY오전/오후0(AM), 1(PM)
HOUR_OF_AMPM(12시간) 시간0 ~ 11
CLOCK_HOUR_OF_AMPM(12시간) 시간1 ~ 12
MINUTE_OF_HOUR0 ~ 59
SECOND_OF_MINUTE0 ~ 59
MILLI_OF_SECOND밀리초0 ~ 999
MICRO_OF_SECOND마이크로초0 ~ 999,999
NANO_OF_SECOND나노초0 ~ 999,999,999
INSTANT_SECONDS타임스탬프-2^63 ~ 2^63-1 (long)
OFFSET_SECONDSUTC기준 오프셋 초-64800 ~ 64800 (±18시간)
  • 주요 메서드
Method반환타입설명
.isSupportedBy(TemporalAccessor)boolean지정된 TemporalAccessor가 해당 필드를 지원하는지 확인합니다.
.getFrom(TemporalAccessor)long해당 필드의 값을 가져옵니다.
.adjustInto(Temporal, long)Temporal해당 필드의 값을 설정한 새로운 Temporal 객체를 반환합니다.
.range()ValueRange해당 필드의 유효 범위를 반환합니다.

예시코드

import java.time.LocalDate;
import java.time.temporal.ChronoField;
import java.time.temporal.ValueRange;

LocalDate today = LocalDate.now();
int year = today.get(ChronoField.YEAR);
int month = today.get(ChronoField.MONTH_OF_YEAR);
int day = today.get(ChronoField.DAY_OF_MONTH);
System.out.println("Year: " + year); // 출력: Year: 2024
System.out.println("Month: " + month); // 출력: Month: 8
System.out.println("Day: " + day); // 출력: Day: 29

LocalDate adjustedDate = today.with(ChronoField.YEAR, 2025);
System.out.println("Adjusted Date: " + adjustedDate); // 출력: Adjusted Date: 2025-08-29

ValueRange range = ChronoField.DAY_OF_MONTH.range();
System.out.println("Day of Month Range: " + range); // 출력: Day of Month Range: 1 - 28/31

2.2. java.time의 핵심 인터페이스 : Temporal 계열 인터페이스

  • java.time 패키지에서 날짜와 시간 작업을 효과적으로 수행하기 위해 설계된 여러 인터페이스들이 존재합니다.
    • 이 중에서 가장 핵심적인 역할을 하는 것이 Temporal 계열의 인터페이스들입니다.
    • 이들 인터페이스는 날짜와 시간 객체의 조작, 계산, 비교, 조정 등을 가능하게 하며, java.time 패키지 내의 여러 클래스들이 이러한 인터페이스를 구현하고 있습니다.
  • Temporal 계열 인터페이스의 상속 및 구현 관계
    • TemporalAccessor --(상속)--> Temporal --(구현)--> LocalDateTime, ZonedDateTime, Instant, ...
    • TemporalAmount --(구현)--> Period, Duration
    • TemporalUnit --(구현)--> ChronoUnit
    • TemporalField --(구현)--> ChronoField

TemporalAccessor

  • TemporalAccessor는 날짜와 시간 객체에서 특정 필드를 읽기 위한 인터페이스입니다.

    • TemporalAccessor는 날짜와 시간 객체를 읽기만 할 수 있으며, 조작은 불가능합니다.
    • 이 인터페이스를 구현하는 클래스들은 특정 날짜 또는 시간 필드의 값을 반환하는 메서드를 제공합니다.
  • 주요 메서드

    • .isSupported(TemporalField field): 특정 필드가 이 객체에서 지원되는지 확인합니다.
    • .getLong(TemporalField field): 지정된 필드의 값을 long 타입으로 반환합니다.
    • .get(TemporalField field): 지정된 필드의 값을 int 타입으로 반환합니다.
    • .range(TemporalField field): 지정된 필드의 유효 범위를 반환합니다.

예시코드

import java.time.LocalDate;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.ChronoField;

TemporalAccessor date = LocalDate.of(2024, 8, 29);
int year = date.get(ChronoField.YEAR);
int month = date.get(ChronoField.MONTH_OF_YEAR);
System.out.println("Year: " + year + ", Month: " + month); // 출력: Year: 2024, Month: 8

Temporal

  • TemporalTemporalAccessor를 상속받아 날짜와 시간 객체를 읽을 뿐만 아니라 조작할 수 있는 기능을 추가로 제공하는 인터페이스입니다.

    • 이 인터페이스는 날짜와 시간 객체에서 값을 더하거나 빼고, 특정 필드의 값을 설정하는 등의 작업을 수행할 수 있게 합니다.
  • 주요 메서드

    • .with(TemporalField field, long newValue): 지정된 필드의 값을 새로 설정한 객체를 반환합니다.
    • .plus(long amountToAdd, TemporalUnit unit): 지정된 단위의 값을 더한 객체를 반환합니다.
    • .minus(long amountToSubtract, TemporalUnit unit): 지정된 단위의 값을 뺀 객체를 반환합니다.
    • .until(Temporal endExclusive, TemporalUnit unit): 현재 객체와 종료 객체 사이의 차이를 지정된 단위로 계산하여 반환합니다.
      • 참고로 ChronoUnit.단위.between()과는 약간 차이가 있는데, .until은 더 일반적이고 다양한 단위로 차이를 계산할 수 있습니다.

예시코드

import java.time.LocalDate;
import java.time.temporal.Temporal;
import java.time.temporal.ChronoUnit;

Temporal date = LocalDate.of(2024, 8, 29);
Temporal nextWeek = date.plus(1, ChronoUnit.WEEKS);
System.out.println("Next Week: " + nextWeek); // 출력: Next Week: 2024-09-05

TemporalAmount

  • TemporalAmount는 시간의 양을 나타내는 인터페이스로, PeriodDuration 클래스가 이를 구현합니다.

    • 이 인터페이스는 특정 양의 시간(예: "3일", "2시간")을 나타내며, 이 양을 날짜나 시간 객체에 더하거나 뺄 수 있습니다.
  • 주요 메서드

    • .get(TemporalUnit unit): 지정된 단위의 값을 반환합니다.
    • .getUnits(): 이 시간 양에서 사용 가능한 단위의 목록을 반환합니다.
    • .addTo(Temporal temporal): 지정된 Temporal 객체에 이 시간 양을 더한 새로운 객체를 반환합니다.
    • .subtractFrom(Temporal temporal): 지정된 Temporal 객체에서 이 시간 양을 뺀 새로운 객체를 반환합니다.

예시코드

  • TemporalAmount로 따로 쓰이지는 않기때문에 이를 구현한 Period를 예시로 가져왔습니다.
import java.time.LocalDate;
import java.time.Period;

LocalDate today = LocalDate.of(2024, 8, 29);
Period period = Period.ofDays(10);
LocalDate tenDaysLater = today.plus(period);
System.out.println("Ten Days Later: " + tenDaysLater); // 출력: Ten Days Later: 2024-09-08

2.3. 날짜 및 시간 조정 인터페이스 : TemporalAdjuster

  • TemporalAdjusterjava.time 패키지에서 날짜와 시간 객체를 조정하는 데 사용되는 전략 인터페이스입니다.
    • 이 인터페이스를 사용하면 특정 날짜나 시간에 대해 다양한 조정 작업을 수행할 수 있습니다. - 예를 들어, 날짜를 다음 월의 첫 번째 일로 변경하거나, 다음 주의 특정 요일로 설정하는 등의 작업을 수행할 수 있습니다.

TemporalAdjuster 소개

  • TemporalAdjusterTemporal 객체를 받아서 그 값을 조정한 후 새로운 Temporal 객체를 반환하는 함수형 인터페이스입니다.
    • 이 인터페이스는 날짜와 시간을 표준적인 방법으로 조정할 수 있게 해주며, 복잡한 날짜 조정 로직을 간단하고 재사용 가능하게 만듭니다.

TemporalAdjuster의 주요 메서드

  • .adjustInto(Temporal temporal): 주어진 Temporal 객체를 조정하고, 조정된 새로운 Temporal 객체를 반환합니다.
    • 이 메서드는 특정 날짜나 시간 필드를 변경하거나, 주어진 규칙에 따라 날짜와 시간을 조정하는 데 사용됩니다.
  • 자바에서는 사용자가 직접 TemporalAdjuster를 구현하여 커스텀 날짜 및 시간 조정을 할 수 있습니다. 이를 통해 더욱 복잡한 조정 로직을 적용할 수 있습니다.
import java.time.LocalDate;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalField;
import java.time.temporal.ChronoField;
import java.time.DayOfWeek;
import java.time.temporal.TemporalAdjusters;

public class NextMonthFirstMondayAdjuster implements TemporalAdjuster {
    @Override
    public Temporal adjustInto(Temporal temporal) {
        // 다음 달의 첫 번째 날로 이동
        Temporal firstDayOfNextMonth = temporal.with(TemporalAdjusters.firstDayOfNextMonth());
        // 첫 번째 월요일로 이동
        return firstDayOfNextMonth.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
    }
}

// 사용 예시
LocalDate today = LocalDate.of(2024, 8, 29);
LocalDate nextMonthFirstMonday = today.with(new NextMonthFirstMondayAdjuster());
System.out.println("Next Month's First Monday: " + nextMonthFirstMonday); // 출력: Next Month's First Monday: 2024-09-02

TemporalAdjusters

  • java.time.temporal.TemporalAdjusters 클래스는 자주 사용되는 TemporalAdjuster를 정적(static) 메서드로 제공합니다.
  • 주로 Temporal객체의 .with()메서드에서 쓰입니다.

TemporalAdjusters의 주요 내장 메서드

TemporalAdjusters설명예시
.firstDayOfMonth()현재 날짜의 해당 월 첫 번째 일로 조정합니다..with(TemporalAdjusters.firstDayOfMonth())
.lastDayOfMonth()현재 날짜의 해당 월 마지막 날로 조정합니다..with(TemporalAdjusters.lastDayOfMonth())
.firstDayOfNextMonth()현재 날짜의 다음 달 첫 번째 날로 조정합니다..with(TemporalAdjusters.firstDayOfNextMonth())
.next(DayOfWeek)현재 날짜 이후의 가장 가까운 특정 요일로 조정합니다..with(TemporalAdjusters.next(DayOfWeek.FRIDAY))
.nextOrSame(DayOfWeek)현재 날짜 또는 이후의 가장 가까운 특정 요일로 조정합니다..with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY))
.previous(DayOfWeek dayOfWeek)현재 날짜 이전의 가장 가까운 특정 요일로 조정합니다..with(TemporalAdjusters.previous(DayOfWeek.MONDAY))
.previousOrSame(DayOfWeek dayOfWeek)현재 날짜 또는 이전의 가장 가까운 특정 요일로 조정합니다..with(TemporalAdjusters.previousOrSame(DayOfWeek.THURSDAY))

TemporalAdjusters 예시

import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.time.DayOfWeek;

LocalDate today = LocalDate.of(2024, 8, 29);

// 다음 월의 첫 번째 날로 조정
LocalDate firstDayOfNextMonth = today.with(TemporalAdjusters.firstDayOfNextMonth());
System.out.println("First Day of Next Month: " + firstDayOfNextMonth); // 출력: First Day of Next Month: 2024-09-01

// 다음 금요일로 조정
LocalDate nextFriday = today.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
System.out.println("Next Friday: " + nextFriday); // 출력: Next Friday: 2024-08-30

마무리

  • 이번 포스팅에서는 java.time 패키지에서 날짜와 시간을 조작하고 계산하는 데 필수적인 ChronoUnitChronoField 클래스, 그리고 다양한 시간 관련 작업을 수행할 수 있게 하는 Temporal 계열 인터페이스에 대해 알아보았습니다.
    • 이러한 도구들을 이해하고 활용함으로써, 날짜와 시간 작업을 더욱 효율적이고 직관적으로 처리할 수 있게 됩니다.
  • 특히, TemporalAdjuster와 같은 인터페이스는 날짜와 시간의 복잡한 조정 작업을 단순하고 명확하게 수행할 수 있도록 도와줍니다.
    • 커스텀 TemporalAdjuster를 구현하여 프로젝트의 특정 요구 사항에 맞는 조정을 수행할 수도 있습니다.
    • 또한 내장된 TemporalAdjusters를 사용하면 자주 발생하는 날짜 조정 작업을 쉽게 처리할 수 있습니다.
  • 다음 포스팅에서는 날짜와 시간의 문자열 파싱과 포맷팅에 대해 다룰 예정입니다.
    • 이 주제에서는 날짜와 시간을 문자열로 변환하거나, 문자열을 날짜와 시간 객체로 변환하는 방법을 다룰 것입니다.
    • 메서드는 간단하지만, Formatter 패턴이 정리할게 많아서 따로 정리하게 되었습니다..
profile
일 때문에 포스팅은 잠시 쉬어요 ㅠ 바쁘다 바빠 모두들 화이팅! // Machine Learning (AI) Engineer & BackEnd Engineer (Entry)

0개의 댓글