14 December 2012
One of the exciting new features coming up in Java 8 is a new date and time library, which is defined by JSR-310. Its also a project that I've helping out on by trying to encourage more developers to give feedback on and by contributing code myself. Threeten has been designed by the lead developer of Jodatime - the most popular third party library in this space - but it differs in a few key ways. This is the first of a series of introductory articles on JSR-310, describing a few core concepts and classes. In the future I plan to cover Timezones, Non-ISO Calendaring Systems and how to use JSR-310 inside your application.
The first classes that you may encounter when using Threeten are LocalDate and Local time - these model the core values of a date and a time within the ISO Calendaring System in the local timezone. They are local in the sense that they represent date and time from the context of the observer. Concepts like Timezones which disambiguate between the contexts of different observers are put to one side here. The Local* classes are appropriate for times when you don't need to disambiguate between such contexts. A desktop application might be one of those times - or if one was trying to provide a human readable time amount since an event. These classes can even be used for representing time on a globally distributed system, providing all the servers are in the same timezone.
There is also a composite class called LocalDateTime, which is a pair of LocalDate and LocalTime. You may be wondering why you have three classes to support this, and not a single class that reporsents all three local values. Martin Fowler explains about the concept of a time point here, and gives a very in depth explanation of this topic.
All the core classes in Threeten are constructed by fluent factory methods. When constructing a value by its constituent fields the factory is called of, when converting from another type, the factory is called from. There are also parse methods which take in strings. Here are some examples:
// The current date and time LocalDateTime.now(); // construct from values LocalDate.of(2012, 12, 12); LocalDate.of(2012, Month.DECEMBER, 12); // Somewhere in the middle of 1970 LocalDate.ofEpochDay(150); // the train I took home today LocalTime.of(17, 18); // From a String LocalTime.parse("10:15:30");
Standard Java getter conventions are used in order to obtain values from JSR-310 Classes.
LocalDateTime timePoint = ... LocalDate theDate = timePoint.getDate(); int monthAsInt = timePoint.getMonthValue(); Month month = timePoint.getMonth(); int day = timePoint.getDayOfMonth(); day = timePoint.getDayOfYear(); timePoint.getSecond(); timePoint.getNano();
You can also alter the object values in order to perform calculations. Since all core classes are immutable in JSR-310 these methods are called 'with' and return new objects, rather than using setters. There are also methods for calculations based on the different fields.
LocalDateTime timePoint = ... // Set the value, returning a new object LocalDateTime another = timePoint.withDayOfMonth(10).withYear(2010); // You can use direct manipulation methods, or pass a value and field pair LocalDateTime yetAnother = another.plusWeeks(3).plus(3, WEEKS);
JSR-310 also has the concept of an adjuster, which is a block of code that can be used in order to wrap up common processing logic. You can either write a 'WithAdjuster' - which is used to set one or more fields, or a 'PlusAdjuster' which is used to add/subtract some fields. Value classes can also act as adjusters, in which case they update the values of the fields that they represent. There are built in adjusters defined by JSR-310, but you can write your own adjusters if you have specific business logic that you wish to reuse.
import static javax.time.calendrical.DateTimeAdjusters.*; LocalDateTime timePoint = ... // Statically imported (see above) foo = timePoint.with(lastDayOfMonth()); bar = timePoint.with(firstDayOfYear()); // Adjusters can also be parameterised timePoint.with(lastInMonth(TUESDAY)); timePoint.with(previousOrSame(WEDNESDAY)); // Using value classes as adjusters timePoint.with(LocalTime.now());
JSR-310 tries to support different precision time-points by offering types to represent a Date, a Time and Date with Time, but obviously there are notions of precision that is more fine grained than this. The truncateTo method exists in order to support such use cases, and allows you to truncate a value to a field.
LocalDate date = ... date.truncatedTo(DAYS); LocalTime time = ... time.truncatedTo(MICROS); time.truncatedTo(SECONDS);
ANSI SQL defines a number of types for Dates and Times. The SQL DATE type corresponds to a LocalDate, TIME corresponds to a LocalTime, and TIMESTAMP corresponds to a LocalDateTime.
Hopefully this has been an easy to follow introduction, and in Part 2 I plan to be cover Timezones and Periods.