In the Java world, working with dates – and time in general - has always been quite problematic. A series of design problems makes use of current API complex and bug prone. JSR-310 to the rescue! The new date and time API, still in development and to be integrated into version 7 of the Java SE platform, promises to finally end this headache that 11 out of 10 Java developers certainly have had to endure.
Problems with the Current API
Everybody agree that the Java’s date and time current API, exposed mainly through java.util.Date and java.util.Calendar classes, presents a series of inconveniences. Among them:
- No classes representing concepts rather common as a date without time, time without date or even a period or interval. Because of that, the developer ends up using the API in a manner different from that for which it was designed.
- The objects are not immutable, requiring external synchronization in a multi-thread environment.
- Classes are limited to represent the date as an incremental number from an initial time (epoch). Besides being counter-intuitive, this approach makes difficult to manipulate the objects adequately.
These are exactly some of the problems that the JSR-310 proposes to solve.
The main features of JSR-310 are:
- Based on ISO-8601 - International Standard for representing dates and times.
- Thread-safe - Its main objects are immutable.
- More cohesion and readability-classes and their methods’ responsibilities are better defined and their names represent these responsibilities more clearly.
- More Extensible - The API provides a set of extension points through which - mainly through the Strategy design pattern - You can customize and extend the behavior of the API, facilitating certain tasks of daily life.
- Two different scales: machine (representing the passage of time using a single incremental number) and Human (representing the passage of time through the value of a number of fields, such as year, month, hour, etc.).
Concepts and main classes
The JSR-310 was built on some basic concepts, which reflects on the main classes of the API.
Instants represent a specific moment in a timeline with nanosecond precision. An example of an instant would be "June 3, 1983 the 12:03:00.0 UTC". Alternatively, a moment can be defined as a shift, in nanoseconds, from a default starting point - the epoch (which remains midnight on January 1, 1970).
There are several classes that represent a moment in the JSR-310 API : Instant, OffSetDateTime and ZonedDateTime.
Instant is one of the most basic API classes. It uses the machine scale. It should be seen as a substitute for java.util.Date. It has methods for comparison with other Instant and addition and subtraction of certain duration (remembering that the class is immutable)
Instant now= Clock.systemDefaultZone().instant(); Instant oneMoreMinute= now.plusSeconds(60); //returns a new Instant! Boolean test = now.isAfter(oneMoreMinute); //false
OffSetDateTime represents a day, time of day and a shift of the UTC (coordinated universal time). It uses, therefore, human scale.
OffsetDateTime today= Clock.systemDefaultZone().offsetDateTime(); OffsetDateTime birthday= OffsetDateTime.of(2009, MonthOfYear.NOVEMBER, 24,19,20,15,ZoneOffset.hours(-3)); System.out.println(today); //2009-11-24T19:20:15-03:00
ZonedDateTime is similar to OffSetDateTime, incorporating the ID of an area, such as America/New_York. This information is important as the offset from UTC may vary throughout the year according to the region (during daylight saving time, for example). When capturing these variations is important for business, a ZonedDateTime should be used.
TimeZone timeZone = TimeZone.of("Europe/Paris"); ZonedDateTime now= Clock.system(timeZone).zonedDateTime(); System.out.println(now); //current time in Paris time zone
Partials are representations of date/time witch are not sufficient to specify one point on a timeline. "December 25" or "12:15" are examples of partials. Since they don’t determine a specific instant, it´s impossible to represent them as a nanosecond shift from epoch.
Some examples of partial in the API: MonthDay (representing a day in a month), Localtime (time with no date!) And LocalDate (Date without time!).
MonthDay easter= MonthDay.of(MonthOfYear.APRIL, 4); LocalDate today= Clock.system(TimeZone.UTC).today(); Year year= today.toYear(); boolean leap= year.isLeap(); // is the current year leap? LocalDateTime birthday= LocalDateTime.of(1983, MonthOfYear.JUNE, 3, 12, 00); System.out.println(birthday); LocalDateTime oneMonthAfter= birthday.plusMonths(1); System.out.println(oneMonthAfter); System.out.println(birthday.isBefore(oneMonthAfter)); //true
Duration represents a certain amount of time with nanosecond precision. Very similar to the concept of Period, differs from it because it represents a certain amount of instants. In the API, the main class that represents duration is Duration.
long seconds= 60L; Duration duration = Duration.seconds(seconds); // creates a one minute duration Instant instant1 = Clock.system(TimeZone.UTC).instant(); //current instant Instant instant2 = instant1.plus(duration); //new instant crated adding a duration to another instant Duration duration2 = Duration.durationBetween(instant1, instant2); // duration created from 2 instants boolean equals = duration.equals(duration2);//true System.out.println(equals);
As durations, periods represent a certain amount of time. Periods are represented, however, through a number of fields (year, month, time). In the API, periods are represented mainly by the class Period.
Period thePeriod = Period.years(8); // creates a eight years period LocalDate data = Clock.system(TimeZone.UTC).today(); LocalDate eightYearsFromNow= data.plus(thePeriod); //Adds the period to the current date. System.out.println(eightYearsFromNow);
As mentioned early, the JSR-310 offers some extension points, so that you can customize its behavior and implement some functionality in a more easy and straightforward way. Some of these extension points are:
- Adjusters: Used to "adjust" dates, returning another date with a certain desired characteristic (a specific day or time, for example). The API provides some built-in Adjusters, like the one used to adjust a date to the last day of the month, for example.
- Resolvers: Indicate how to handle an invalid date (if any operation resolve to Feb. 29 in a not leap year, for example). In this case the API also has default implementations, the most common being the one that resolves to the next valid date.
- Matchers: Perform Boolean queries and dates and times, to know if the date has a specific characteristic (one day or time specific, for example). As in other cases, standards implementations are provided, to determine, for example, if the date belongs to a given year.
This post was about the main features of JSR 310, the new Java API for date and time that might be delivered together with the 7th version of the platform’s standard edition. This API provides significant improvements over the current API, as it was observed throughout the post.
http://wiki.java.net/bin/view/Projects/DateTimeEDR1 - JSR-310 Home at jana.net. Here you can find reference, user guide, java docs a reference implementation. Remember thught that the specificaion is still at development!
Revista Java Magazine yearVII 69 edition - Excellent article on the JSR-310.