Java/개념

[Java] Java 8에 추가된 LocalDate, LocalTime, LocalDateTime

TheWing 2020. 11. 2. 22:53

Java 8에 추가된 LocalDate,LocalTime,LocalDateTime

  • 이전 포스팅에 이어 포스팅하겠습니다.

2020/11/02 - [Java/개념] - Java 에서 Date, Calendar클래스가 왜 Deprecated됐는지?

  • 이번 포스팅은 java.time 패키지의 LocalDate,LocalTime,LocalDateTime 에 대해 알아보겠습니다.

Java의 Time API 흐름

  • Date(jdk 1.0) → Calendar(jdk.1.1) → java.time(jdk 1.8)

LocalDate,LocalTime,LocalDateTime 클래스들의 공통점

  • TimeZone 개념을 가지고 있지 않기 때문에 TimeZone에 따라 시간 변환이 불가능합니다.

java.time 패키지

  • 이와같이 DateCalendar의 단점을 해소하기위해 JDK 1.8 버전에서 java.time 패키지에 LocalDateTimeTimeZone 개념까지 포함할 수 있는 ZonedDateTime이 추가되었다. 따라서 이전보다 안전하고 편하게 날짜를 계산할 수 있다.

LocalDate

  • LocalDate 클래스는 날짜를 표현하는데 사용된다.
  • TimeZone 개념이 필요없는 날짜 정보를 나타내기 위해서 사용된다.

LocalDate 사용예제

LocalDate nowDate = LocalDate.now(); //현재 날짜
LocalDate ofDate = LocalDate.of(2020, 11,02); //지정 날짜
LocalDate parseDate = LocalDate.parse("2020-11-02"); //문자열로 날짜 지정
System.out.println(nowDate);
System.out.println(ofDate);
System.out.println(parseDate);
System.out.println("getYear="+parseDate.getYear());
System.out.println("getMonth="+parseDate.getMonth());
System.out.println("getMonthValue="+parseDate.getMonthValue());
System.out.println("getDayOfYear="+parseDate.getDayOfYear());
System.out.println("getDayOfMonth="+parseDate.getDayOfMonth());
System.out.println("getDayOfWeek="+parseDate.getDayOfWeek());
System.out.println("getDayOfMonth="+parseDate.getDayOfMonth());
System.out.println("isLeapYear="+parseDate.isLeapYear());
  • 결과
2020-11-02
2020-11-02
2020-11-02
getYear=2020
getMonth=NOVEMBER
getMonthValue=11
getDayOfYear=307
getDayOfMonth=2
getDayOfWeek=MONDAY
getDayOfMonth=2
isLeapYear=true
  • 날짜 정보만 찍게 된다. 아래 사용된 메소드를 확인해보자

리턴 타입

메소드 및 매개 변수

설명

int

getYear()

해당 날짜 객체의 연도(YEAR) 값을 리턴

Month

getMonth()

해당 날짜 객체의 월(MONTH_OF_YEAR)의 값을 Enum Month 클래스의 값(JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER) 으로 리턴

int

getMonthValue()

해당 날짜 객체의 월(MONTH_OF_YEAR) 필드의 값을 리턴함. (1~12)

int

getDayOfYear()

해당 날짜 객체의 일(DAY_OF_YEAR) 필드의 값을 리턴 (1~365, 윤년이면 366)

int

getDayOfMonth()

해당 날짜 객체의 일(DAY_OF_MONTH) 필드의 값을 리턴 (1~31)

DayOfWeek

getDayOfWeek()

해당 날짜 객체의 요일(DAY_OF_WEEK) 필드의 값을 Enum DayOfWeek 클래스의 값 요일(MONDAY, TUESDAY, WEDNESDAY..)로 리턴함

boolean

isLeapYear()

윤년여부를 리턴

LocalTime

  • LocalTime 클래스는 시간을 표현하는데 사용된다
  • TimeZone 개념이 필요없는 시간 정보를 나타내기 위해서 사용된다
LocalTime nowTime = LocalTime.now(); //현재 시간
LocalTime ofTime = LocalTime.of(21,30,30); //지정 시간
LocalTime ofNanoTime = LocalTime.of(21,30,30, 30); // 지정 시간(나노초 포함)
LocalTime plusHours = ofTime.plusHours(5);
LocalTime plusMinutes = ofTime.plusMinutes(5);
LocalTime plusSeconds = ofTime.plusSeconds(5);
LocalTime minusHours = ofTime.minusHours(5);
LocalTime minusMinutes = ofTime.minusMinutes(5);
LocalTime minusSeconds = ofTime.minusSeconds(5);
System.out.println(nowTime);
System.out.println(ofTime);
System.out.println(ofNanoTime);
System.out.println("plusHours="+plusHours);
System.out.println("plusMinutes="+plusMinutes);
System.out.println("plusSeconds="+plusSeconds);
System.out.println("minusHours="+minusHours);
System.out.println("minusMinutes="+minusMinutes);
System.out.println("minusSeconds="+minusSeconds);
System.out.println("getHour="+ofTime.getHour());
System.out.println("getMinute="+ofTime.getMinute());
System.out.println("getSecond="+ofTime.getSecond());
System.out.println("getNano="+ofTime.getNano());
  • 결과
21:39:17.659400
21:30:30
21:30:30.000000030
plusHours=02:30:30
plusMinutes=21:35:30
plusSeconds=21:30:35
minusHours=16:30:30
minusMinutes=21:25:30
minusSeconds=21:30:25
getHour=21
getMinute=30
getSecond=30
getNano=0
  • 시간 정보만 찍게 된다. 아래 사용된 메소드를 확인해보자

리턴 타입

메소드 및 매개 변수

설명

int,long

get(TemporalField field)

해당 날짜 객체의 명시된 필드의 값을 int형이나 long형으로 리턴

int

getYear()

해당 날짜 객체의 연도(YEAR) 필드의 값을 리턴

Month

getMonth()

해당 날짜 객체의 월(MONTH_OF_YEAR) 필드의 값을 Enum Month 클래스를 이용하여 리턴

int

getMonthValue()

해당 날짜 객체의 월(MONTH_OF_YEAR) 필드의 값을 리턴. (1~12)

int

getDayOfMonth()

해당 날짜 객체의 일(DAY_OF_MONTH) 필드의 값을 리턴 (1~31)

int

getDayOfYear()

해당 날짜 객체의 일(DAY_OF_YEAR) 필드의 값을 리턴 (1~365, 윤년이면 366)

DayOfWeek

getDayOfWeek()

해당 날짜 객체의 요일(DAY_OF_WEEK) 필드의 값을 Enum DayOfWeek클래스 를 이용하여 리턴

int

getHour()

해당 시간 객체의 시(HOUR_OF_DAY) 필드의 값을 리턴.

int

getMinute()

해당 시간 객체의 분(MINUTE_OF_HOUR) 필드의 값을 리턴

int

getSecond()

해당 시간 객체의 초(SECOND_OF_MINUTE) 필드의 값을 리턴

int

getNano()

해당 시간 객체의 나노초(NANO_OF_SECOND) 필드의 값을 리턴

  • Calendar 클래스의 단점 이였던 1월을 0으로 표현한것과 요일을 일요일부터 1로 표현했었습니다.
  • java.time 패키지에서는 1월을 1로 표현하여 월의 범위가 1~12가 되었고 요일은 월요일부터 1로 표현하여서 범위가 1~7로 변경되었습니다.

LocalDateTime

  • LocalDateTime 클래스는 날짜와 시간 정보를 모두 표현합니다.

LocalDateTime 예제

LocalDateTime nowDateTime = LocalDateTime.now(); //현재 시간
LocalDateTime nowDateTime2 = LocalDateTime.of(LocalDate.now(), LocalTime.now()); // 현재 날짜와 시간
LocalDateTime paresDateTime = LocalDateTime.parse("2020-11-02T21:59:59.999"); // 문자열 지정된 날짜 시간
LocalDateTime ofDateTime = LocalDateTime.of(2020,11,02,21,59,00); //정수형으로 지정된 날짜 시간 
LocalDateTime ofNanoDateTime = LocalDateTime.of(2020,11,02,21,59,00,55); //나노초 포함
LocalDateTime ofDateTime2 = Year.of(2020).atMonth(11).atDay(02).atTime(14, 15); //시간 분
LocalDateTime ofDateTime3 = Year.of(2020).atMonth(11).atDay(02).atTime(14, 15, 50); //시간 분 초
LocalDateTime ofDateTime4 = Year.of(2020).atMonth(11).atDay(02).atTime(14, 15, 50,3); // 시간 분 초 나노초
System.out.println("nowDateTime = " + nowDateTime);
System.out.println("nowDateTime2 = " + nowDateTime2);
System.out.println("paresDateTime = " + paresDateTime);
System.out.println("ofDateTime = " + ofDateTime);
System.out.println("ofNanoDateTime = " + ofNanoDateTime);
System.out.println("ofDateTime2 = " + ofDateTime2);
System.out.println("ofDateTime3 = " + ofDateTime3);
System.out.println("ofDateTime4 = " + ofDateTime4);
System.out.println("getDayOfMonth = " + nowDateTime.getDayOfMonth());
System.out.println("getDayOfWeek = " + nowDateTime.getDayOfWeek());
System.out.println("getDayOfYear = " + nowDateTime.getDayOfYear());
System.out.println("getYear = " + nowDateTime.getYear());
System.out.println("getHour = " + nowDateTime.getHour());
System.out.println("getMinute = " + nowDateTime.getMinute());
System.out.println("getSecond = " + nowDateTime.getSecond());
System.out.println("getNano = " + nowDateTime.getNano());
System.out.println("plusYears = " + nowDateTime.plusYears(1));
System.out.println("plusMonths = " + nowDateTime.plusMonths(1));
System.out.println("plusDays = " + nowDateTime.plusDays(1));
System.out.println("plusHours = " + nowDateTime.plusHours(1));
System.out.println("plusMinutes = " + nowDateTime.plusMinutes(1));
System.out.println("plusSeconds = " + nowDateTime.plusSeconds(1));
  • 결과
nowDateTime = 2020-11-02T22:06:02.256149500
nowDateTime2 = 2020-11-02T22:06:02.257147
paresDateTime = 2020-11-02T21:59:59.999
ofDateTime = 2020-11-02T21:59
ofNanoDateTime = 2020-11-02T21:59:00.000000055
ofDateTime2 = 2020-11-02T14:15
ofDateTime3 = 2020-11-02T14:15:50
ofDateTime4 = 2020-11-02T14:15:50.000000003
getDayOfMonth = 2
getDayOfWeek = MONDAY
getDayOfYear = 307
getYear = 2020
getHour = 22
getMinute = 6
getSecond = 2
getNano = 256149500
plusYears = 2021-11-02T22:06:02.256149500
plusMonths = 2020-12-02T22:06:02.256149500
plusDays = 2020-11-03T22:06:02.256149500
plusHours = 2020-11-02T23:06:02.256149500
plusMinutes = 2020-11-02T22:07:02.256149500
plusSeconds = 2020-11-02T22:06:03.256149500
plusNanos = 2020-11-02T22:06:02.256149501
  • LocalDate 클래스 와 LocalTime 클래스의 메소드들이 겹치는 부분이 많기 때문에 메소드는 추론이 가능할 것이다
  • ofDateTime 변수에서 정적 메소드 대신에 Year.of() 로 시작하는 것은Fluent API이다. 코드의 가독성이 좋아진다

날짜 비교

LocalDateTime nowDateTime = LocalDateTime.now(); //현재 시간
LocalDateTime nowDateTime2 = LocalDateTime.of(LocalDate.now(), LocalTime.now()); // 현재 날짜와 시간
// nowDateTime 이 nowDateTime2 보다 이전 날짜 인지?
System.out.println(nowDateTime.isBefore(nowDateTime2));
// 동일 날짜 인지?
System.out.println(nowDateTime.isEqual(nowDateTime2));
// nowDateTime 이 nowDateTime2 보다 이후 날짜 인지?
System.out.println(nowDateTime.isAfter(nowDateTime2));
  • 결과
false
true
false
  • 나노초가 까지 비교하므로 나노초가 있는지 없는지 유무 파악이 중요합니다.

시간 비교

LocalTime nowTime = LocalTime.now(); //현재 시간
LocalTime ofTime = LocalTime.of(21,30,30); //지정 시간
System.out.println(nowTime.isBefore(ofTime));
System.out.println(nowTime.isAfter(ofTime));
  • 결과
false
true

날짜와 시간 객체의 비교

  • LocalDate와 LocalTime 클래스에도 객체를 비교할 수 있는 compareTo() 메소드가 오버라이딩되어 있습니다.
  • 하지만 더욱 편리하게 날짜와 시간 객체를 서로 비교할 수 있도록 다음과 같은 메소드를 제공합니다.
  • isEqual() 메소드 : equals() 메소드와는 달리 오직 날짜만을 비교함. (LocalDate 클래스에서만 제공)
  • isBefore() 메소드 : 두 개의 날짜와 시간 객체를 비교하여 현재 객체가 명시된 객체보다 앞선 시간인지를 비교함.
  • isAfter() 메소드 : 두 개의 날짜와 시간 객체를 비교하여 현재 객체가 명시된 객체보다 늦은 시간인지를 비교함.
  • 등등 많은 메소드가 있다

불변(Immutable),Thread-safe

  • API를 살펴보면
* This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
* class; use of identity-sensitive operations (including reference equality
* ({@code ==}), identity hash code, or synchronization) on instances of
* {@code LocalDateTime} may have unpredictable results and should be avoided.
* The {@code equals} method should be used for comparisons.
*
* @implSpec
* This class is immutable and thread-safe.
*
* @since 1.8
*/
  • java.time 패키지들은 String 클래스처럼 Immutable 하다.
  • 멀티 쓰레드 환경에서 Thread-safe하다
  • 앞 포스팅에서Calendar 클래스와 Date 클래스는 mutable 하다고 했었다.
    • 멀티 쓰레드 환경에서 여러 쓰레드가 동시에 같은 객체에 접근이 가능해서 변경 가능한 객체의 데이터가 변경되어서 잘못된 값을 가질 가능성이 있었다.