Java Date - 날짜와 시간 조회 및 조작

날짜 조회하기

날짜와 시간 조회에는 날짜와 시간 항목 중 어떤 필드로 조회할 것인지 정할 필요가 있다.
날짜와 시간의 필드를 갖고 있는 ChronoField 클래스로 사용한다.

먼저 LocalDateTime 객체타입의 dt 변수로 선언한다.

LocalDateTime dt = LocalDateTime.of(2028, 8, 28, 14, 29, 59);
System.out.println(dt);

2028-08-28T14:29:59

TemporalAccessor.get(TemporalField field)

  • LocalDateTime 포함한 특정 시점 시간을 제공하는 클래스는 TemporalAccessor 인터페이스로 포함되어 구현되어 있다.
  • TemporalAccessor 특정 시점의 시간을 조회하는 기능을 제공
  • get(TemporalField field) 호출 시 어떤 날짜와 시간 필드로 조회할지 TemporalField 구현인 ChronoField 인수로 전달할 수 있다.

해당 시간대로 ChronoField 각 날짜 필드 별 조회해보도록 한다.


YEAR 연도 조회

System.out.println("YEAR = " + dt.get(ChronoField.YEAR));

YEAR = 2028

LocalDateTime 객체의 get 메소드로 ChronoField 필드로 연도를 조회하였다.


MONTH_OF_YEAR 몇 월인지 조회하기

System.out.println("MONTH_OF_YEAR = " + dt.get(ChronoField.MONTH_OF_YEAR));

MONTH_OF_YEAR = 8


DAY_OF_MONTH 몇 일인지 조회하기

System.out.println("DAY_OF_MONTH = " + dt.get(ChronoField.DAY_OF_MONTH));

DAY_OF_MONTH = 28


HOUR_OF_DAY 몇 시인지 조회하기

System.out.println("HOUR = " + dt.get(ChronoField.HOUR_OF_DAY));

HOUR = 14


MINUTE_OF_HOUR 몇 분인지 조회하기

System.out.println("MINUTE = " + dt.get(ChronoField.MINUTE_OF_HOUR));

MINUTE = 29


SECOND_OF_MINUTE 몇 초인지 조회하기

System.out.println("SECOND = " + dt.get(ChronoField.SECOND_OF_MINUTE));

SECOND = 59


편의 메소드 제공

get(ChronoField ...) 형태로 계속 호출 대신 다른 방법으로 출력 하는 방법도 있다.

System.out.println("편의 메소드 제공");
System.out.println("YEAR = " + dt.getYear());
System.out.println("MONTH_OF_YEAR = " + dt.getMonth());
System.out.println("DAY_OF_MONTH = " + dt.getDayOfMonth());
System.out.println("HOUR = " + dt.getHour());
System.out.println("MINUTE = " + dt.getMinute());
System.out.println("SECOND = " + dt.getSecond());

편의 메소드 제공
YEAR = 2028
MONTH_OF_YEAR = AUGUST
DAY_OF_MONTH = 28
HOUR = 14
MINUTE = 29
SECOND = 59

  • get(TemporalField field) 코드가 길어지고 번거로운 것으로 자주 사용하는 조회 필드는 간단한 편의메소드로 제공하고 있다.
  • dt.get(ChronoField.DAY_OF_MONTH) -> get.getDayOfMonth()

편의 메소드 없음

자주 사용하지 않는 특정 날짜와 필드에 대한 편의 메소드가 없다. 이 경우 ChronoField 로 직접 찾아 넣어주어야 한다.

System.out.println("편의 메소드 없음");
System.out.println("MINUTE_OF_DAY = " + dt.get(ChronoField.MINUTE_OF_DAY));
System.out.println("SECOND_OF_DAY = " + dt.get(ChronoField.SECOND_OF_DAY));

편의 메소드 없음
MINUTE_OF_DAY = 869
SECOND_OF_DAY = 52199

  • 자주 사용하지 않으므로 편의 메소드가 없음
  • 편의 메소드를 사용하는 것이 가독성이 좋아서 주로 사용하고 편의 메소드가 없는 경우 ChronoField 필드로 직접 호출하도록 한다.

get 메소드는 TemporalAccessor 인터페이스로부터



날짜 및 시간 조정하기

날짜 및 시간 조작에는 어떤 단위로(Unit) 변경할지 정해야 한다. 이럴 때는 ChronoUnit 구현체로 사용한다.

LocalDateTime dt = LocalDateTime.of(2028, 8, 28, 14, 29, 59);
System.out.println(dt);

2028-08-28T14:29:59

위 변수로 계속 이어서 사용하며 조정해보도록 한다.

ChronoUnit.Years - 연도 늘리기

LocalDateTime plusYear = dt.plus(10, ChronoUnit.YEARS);
System.out.println("Plus 10Years: " + plusYear);

Plus 10 Years: 2038-08-28T14:29:59


편의 메소드 - 연도 늘리기

LocalDateTime plusYear = dt.plusYears(10);
System.out.println("Plus 10Years: " + plusYear);

Plus 10 Years: 2038-08-28T14:29:59


Period - 연도 늘리기

Period period = Period.ofYears(10);
LocalDateTime plusYears = dt.plus(period);
System.out.println("Plus 10Years: " + plusYears);

Plus 10Years: 2038-08-28T14:29:59


ChronoUnit.Months - 연도 늘리기

LocalDateTime plusMonths = dt.plus(10, ChronoUnit.MONTHS);
System.out.println("Plus 10MONTHS: " + plusMonths);

Plus 10MONTHS: 2029-06-28T14:29:59


정리

Temporal plus(long amountToAdd, TemporalUnit unit)

  • LocalDateTime 포함한 트겆ㅇ 시점의 시간을 제공하는 클래스는 모두 Temporal 인터페이스로 구현된 것을 볼 수 있다.
  • Temporal 특정 시점의 시간을 조작하는 시간을 포함한다.
  • plus(long amountToAdd, TemporalUnit unit) 호출마다 더하기 할 숫자와 단위를 전달한다.
  • 단위는 ChronoUnit 인수로 전달
  • 실제 인스턴스의 값은 불변이므로 변경되지 않으므로 새 객체로 전달한다.

편의 메소드 사용

  • 자주 사용하는 메소드는 변경 및 조작에도 편의 메소드를 제공한다.
  • dt.plus(10, ChronoUnit.YEARS) -> dt.plusYears(10)

Period 사용한 조작

  • Period 또는 Duration 기간(시간의 간격)을 갖고 있다. 이 것을 이용해 날짜와 시간의 기간을 더할 수 있다.

날짜와 시간의 Temporal 장점

  • 시간을 조회 및 변경에서 TemporalAccessor.get(), Temporal.plus() 인터페이스로 구현 클래스와 무관하게 일관성 있게 조회 및 변경 기능을 진행하였다.
  • LocalDateTime, LocalDate, LocalTime, ZonedDateTime, Instant 구현에 관계 없이 일관성 있는 방법으로 시간을 조회하고 조작한다.

단점

  • 시간 필드를 조회할 수 없는 상황도 생긴다.
  • LocalTime, LocalDate 와 같이 날짜나 시간이 빠진 부분을 조회하면 예외 처리되어 출력하지 않는다.
LocalDate now = LocalDate.now();
System.out.println(now.get(ChronoField.MINUTE_OF_DAY));

Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: MinuteOfDay

대응 방안

  • isSupported 와 같이 필드를 조회할 수 있는지 확인할 수 있는 메소드도 제공한다.
LocalDate now = LocalDate.now();
boolean supported = now.isSupported(ChronoField.MINUTE_OF_DAY);
System.out.println(supported);

false

LocalDate 시 분 초를 다루지 않기에 ChronoField.MINUTE_OF_DAY 조회 시 false 값으로 출력한다.