Java 8 날짜 / 시간 API 소개

1. 개요

Java 8 은 이전 java.util.Datejava.util.Calendar 의 단점을 해결하기 위해 날짜시간 에 대한 새로운 API를 도입했습니다 .

이 기사의 일부로 기존 날짜달력 API 의 문제부터 시작 하고 새로운 Java 8 날짜시간 API가 문제를 해결하는 방법에 대해 논의 해 보겠습니다 .

또한 LocalDate , LocalTime, LocalDateTime, ZonedDateTime, Period, Duration 및 지원되는 API와 같은 java.time 패키지의 일부인 새로운 Java 8 프로젝트의 일부 핵심 클래스를 살펴볼 것 입니다.

2. 기존 날짜 / 시간 API의 문제

  • 스레드 안전성DateCalendar 클래스는 스레드로부터 안전하지 않으므로 개발자는 동시성 문제를 디버깅하기 어려운 골칫거리를 처리하고 스레드 안전성을 처리하기위한 추가 코드를 작성해야합니다. 반대로 Java 8에 도입 된 새로운 날짜시간 API는 변경이 불가능하고 스레드로부터 안전하므로 개발자의 동시성 문제를 해결합니다.
  • API 설계 및 이해 용이성날짜달력 API는 일상적인 작업을 수행하는 데 부적절한 방법으로 잘못 설계되었습니다. 새로운 날짜 / 시간 API는 ISO 중심이며 날짜, 시간, 기간 및 기간에 대해 일관된 도메인 모델을 따릅니다. 가장 일반적인 작업을 지원하는 다양한 유틸리티 방법이 있습니다.
  • ZonedDateTime – 개발자는 이전 API로 시간대 로직을 처리하기 위해 추가 로직을 작성해야했지만, 새 API에서는 시간대 처리가 Local ZonedDate / Time API로 수행 될 수 있습니다.

3. LocalDate , LocalTimeLocalDateTime 사용

가장 일반적으로 사용되는 클래스는 LocalDate , LocalTimeLocalDateTime 입니다. 이름에서 알 수 있듯이 관찰자의 컨텍스트에서 현지 날짜 / 시간을 나타냅니다.

이러한 클래스는 주로 컨텍스트에 시간대를 명시 적으로 지정할 필요가 없을 때 사용됩니다. 이 섹션의 일부로 가장 일반적으로 사용되는 API를 다룹니다.

3.1. LocalDate 작업

LOCALDATE을 나타내는 ISO 형식 (YYYY-MM-DD)의 시간없이 날짜 .

생일 및 월급 날과 같은 날짜를 저장하는 데 사용할 수 있습니다.

현재 날짜의 인스턴스는 아래와 같이 시스템 시계에서 만들 수 있습니다.

LocalDate localDate = LocalDate.now();

LOCALDATE 특정 일, 월, 연도 대표는 "사용하여 얻을 수 방법"또는 "을 사용하여 구문 분석 "방법을. 예를 들어 아래 코드 스 니펫은 2015 년 2 월 20 일 의 LocalDate 를 나타냅니다 .

LocalDate.of(2015, 02, 20); LocalDate.parse("2015-02-20");

LOCALDATE는 다양한 정보를 얻기 위해 다양한 유틸리티 메소드를 제공한다. 이러한 API 메서드 중 일부를 간단히 살펴 보겠습니다.

다음 코드 스 니펫은 현재 현지 날짜를 가져 와서 하루를 추가합니다.

LocalDate tomorrow = LocalDate.now().plusDays(1);

이 예에서는 현재 날짜를 얻고 한 달을 뺍니다. 열거 형 을 시간 단위로 받아들이는 방법에 유의하십시오 .

LocalDate previousMonthSameDay = LocalDate.now().minus(1, ChronoUnit.MONTHS);

다음 두 코드 예제에서는 "2016-06-12"날짜를 구문 분석하고 각각 요일과 날짜를 가져옵니다. 반환 값에 유의하십시오. 첫 번째는 DayOfWeek 를 나타내는 개체 이고 두 번째 는 월의 서수 값을 나타내는 int 의 두 번째 개체입니다 .

DayOfWeek sunday = LocalDate.parse("2016-06-12").getDayOfWeek(); int twelve = LocalDate.parse("2016-06-12").getDayOfMonth();

윤년에 날짜가 발생하는지 테스트 할 수 있습니다. 이 예에서는 현재 날짜가 윤년인지 테스트합니다.

boolean leapYear = LocalDate.now().isLeapYear();

날짜와 다른 날짜의 관계는 다른 날짜 이전 또는 이후에 발생하도록 결정할 수 있습니다.

boolean notBefore = LocalDate.parse("2016-06-12") .isBefore(LocalDate.parse("2016-06-11")); boolean isAfter = LocalDate.parse("2016-06-12") .isAfter(LocalDate.parse("2016-06-11"));

날짜 경계는 주어진 날짜에서 얻을 수 있습니다. 다음의 두 가지 예에서 우리가 얻을 LocalDateTime 주어진 날짜와의 : 날 (00 2016-06-12T00)의 시작 나타내는 LOCALDATE 각각 월 (2016년 6월 1일)의 시작을 나타냅니다 :

LocalDateTime beginningOfDay = LocalDate.parse("2016-06-12").atStartOfDay(); LocalDate firstDayOfMonth = LocalDate.parse("2016-06-12") .with(TemporalAdjusters.firstDayOfMonth());

이제 현지 시간으로 작업하는 방법을 살펴 보겠습니다.

3.2. LocalTime 작업

로컬 시간을 나타내는 날짜없이 시간을 .

LocalDate 와 유사하게 LocalTime 의 인스턴스는 시스템 시계에서 만들거나 "parse"및 "of"메서드를 사용하여 만들 수 있습니다. 아래에서 일반적으로 사용되는 몇 가지 API를 간략히 살펴보세요.

현재 LocalTime 의 인스턴스는 아래와 같이 시스템 시계에서 만들 수 있습니다.

LocalTime now = LocalTime.now();

아래 코드 샘플 에서는 문자열 표현을 파싱하여 오전 06:30을 나타내는 LocalTime 을 만듭니다 .

LocalTime sixThirty = LocalTime.parse("06:30");

Factory 메서드 "of"를 사용하여 LocalTime 을 만들 수 있습니다 . 예를 들어 아래 코드 는 팩토리 메서드를 사용하여 오전 06:30을 나타내는 LocalTime을 만듭니다 .

LocalTime sixThirty = LocalTime.of(6, 30);

아래 예제 는 문자열을 구문 분석 하여 LocalTime 을 만들고 "plus"API를 사용하여 시간을 추가합니다. 결과는 07:30 AM을 나타내는 LocalTime이됩니다 .

LocalTime sevenThirty = LocalTime.parse("06:30").plus(1, ChronoUnit.HOURS);

아래와 같이 시간, 분, 초와 같은 특정 시간 단위를 얻는 데 사용할 수있는 다양한 getter 메서드를 사용할 수 있습니다.

int six = LocalTime.parse("06:30").getHour();

We can also check if a specific time is before or after another specific time. The below code sample compares two LocalTime for which the result would be true:

boolean isbefore = LocalTime.parse("06:30").isBefore(LocalTime.parse("07:30"));

The max, min and noon time of a day can be obtained by constants in LocalTime class. This is very useful when performing database queries to find records within a given span of time. For example, the below code represents 23:59:59.99:

LocalTime maxTime = LocalTime.MAX

Now let's dive into LocalDateTime.

3.3. Working With LocalDateTime

The LocalDateTime is used to represent a combination of date and time.

This is the most commonly used class when we need a combination of date and time. The class offers a variety of APIs and we will look at some of the most commonly used ones.

An instance of LocalDateTime can be obtained from the system clock similar to LocalDate and LocalTime:

LocalDateTime.now();

The below code samples explain how to create an instance using the factory “of” and “parse” methods. The result would be a LocalDateTime instance representing 20 February 2015, 06:30 AM:

LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);
LocalDateTime.parse("2015-02-20T06:30:00");

There are utility APIs to support addition and subtraction of specific units of time like days, months, year and minutes are available. The below code samples demonstrates the usage of “plus” and “minus” methods. These APIs behave exactly like their counterparts in LocalDate and LocalTime:

localDateTime.plusDays(1);
localDateTime.minusHours(2);

Getter methods are available to extract specific units similar to the date and time classes. Given the above instance of LocalDateTime, the below code sample will return the month February:

localDateTime.getMonth();

4. Using ZonedDateTime API

Java 8 provides ZonedDateTime when we need to deal with time zone specific date and time. The ZoneId is an identifier used to represent different zones. There are about 40 different time zones and the ZoneId are used to represent them as follows.

In this code snippet we create a Zone for Paris:

ZoneId zoneId = ZoneId.of("Europe/Paris"); 

A set of all zone ids can be obtained as below:

Set allZoneIds = ZoneId.getAvailableZoneIds();

The LocalDateTime can be converted to a specific zone:

ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);

The ZonedDateTime provides parse method to get time zone specific date time:

ZonedDateTime.parse("2015-05-03T10:15:30+01:00[Europe/Paris]");

Another way to work with time zone is by using OffsetDateTime. The OffsetDateTime is an immutable representation of a date-time with an offset. This class stores all date and time fields, to a precision of nanoseconds, as well as the offset from UTC/Greenwich.

The OffSetDateTime instance can be created as below using ZoneOffset. Here we create a LocalDateTime representing 6:30 am on 20th February 2015:

LocalDateTime localDateTime = LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);

Then we add two hours to the time by creating a ZoneOffset and setting for the localDateTime instance:

ZoneOffset offset = ZoneOffset.of("+02:00"); OffsetDateTime offSetByTwo = OffsetDateTime .of(localDateTime, offset);

We now have a localDateTime of 2015-02-20 06:30 +02:00. Now let's move on to how to modify date and time values using the Period and Duration classes.

5. Using Period and Duration

The Period class represents a quantity of time in terms of years, months and days and the Duration class represents a quantity of time in terms of seconds and nano seconds.

5.1. Working With Period

The Period class is widely used to modify values of given a date or to obtain the difference between two dates:

LocalDate initialDate = LocalDate.parse("2007-05-10");

The Date can be manipulated using Period as shown in the following code snippet:

LocalDate finalDate = initialDate.plus(Period.ofDays(5));

The Period class has various getter methods such as getYears, getMonths and getDays to get values from a Period object. The below code example returns an int value of 5 as we try to get difference in terms of days:

int five = Period.between(initialDate, finalDate).getDays();

The Period between two dates can be obtained in a specific unit such as days or month or years, using ChronoUnit.between:

long five = ChronoUnit.DAYS.between(initialDate, finalDate);

This code example returns five days. Let's continue by taking a look at the Duration class.

5.2. Working With Duration

Similar to Period, the Duration class is use to deal with Time. In the following code we create a LocalTime of 6:30 am and then add a duration of 30 seconds to make a LocalTime of 06:30:30am:

LocalTime initialTime = LocalTime.of(6, 30, 0); LocalTime finalTime = initialTime.plus(Duration.ofSeconds(30));

The Duration between two instants can be obtained either as a Duration or as a specific unit. In the first code snippet we use the between() method of the Duration class to find the time difference between finalTime and initialTime and return the difference in seconds:

long thirty = Duration.between(initialTime, finalTime).getSeconds();

In the second example we use the between() method of the ChronoUnit class to perform the same operation:

long thirty = ChronoUnit.SECONDS.between(initialTime, finalTime);

Now we will look at how to convert existing Date and Calendar to new Date/Time.

6. Compatibility with Date and Calendar

Java 8 has added the toInstant() method which helps to convert existing Date and Calendar instance to new Date Time API as in the following code snippet:

LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());

The LocalDateTime can be constructed from epoch seconds as below. The result of the below code would be a LocalDateTime representing 2016-06-13T11:34:50:

LocalDateTime.ofEpochSecond(1465817690, 0, ZoneOffset.UTC);

Now let's move on to Date and Time formatting.

7. Date and Time Formatting

Java 8 provides APIs for the easy formatting of Date and Time:

LocalDateTime localDateTime = LocalDateTime.of(2015, Month.JANUARY, 25, 6, 30);

The below code passes an ISO date format to format the local date. The result would be 2015-01-25 :

String localDateString = localDateTime.format(DateTimeFormatter.ISO_DATE);

The DateTimeFormatter provides various standard formatting options. Custom patterns can be provided to format method as well, like below, which would return a LocalDate as 2015/01/25:

localDateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));

We can pass in formatting style either as SHORT, LONG or MEDIUM as part of the formatting option. The below code sample would give an output representing LocalDateTime in 25-Jan-2015, 06:30:00:

localDateTime .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)) .withLocale(Locale.UK);

Let us take a look at alternatives available to Java 8 Core Date/Time APIs.

8. Backport and Alternate Options

8.1. Using Project Threeten

For organization that are on the path of moving to Java 8 from Java 7 or Java 6 and want to use date and time API, project threeten provides the backport capability. Developers can use classes available in this project to achieve the same functionality as that of new Java 8 Date and Time API and once they move to Java 8, the packages can be switched. Artifact for the project threeten can be found in the maven central repository:

 org.threeten threetenbp 1.3.1 

8.2. Joda-Time Library

Another alternative for Java 8 Date and Time library is Joda-Time library. In fact Java 8 Date Time APIs has been led jointly by the author of Joda-Time library (Stephen Colebourne) and Oracle. This library provides pretty much all capabilities that is supported in Java 8 Date Time project. The Artifact can be found in the maven central by including the below pom dependency in your project:

 joda-time joda-time 2.9.4 

9. Conclusion

Java 8 provides a rich set of APIs with consistent API design for easier development.

The code samples for the above article can be found in the Java 8 Date/Time git repository.