Martin @ Blog

software development and life.

Flower

Java Date and Time API and JSR-310

Dutch version can be found at the Finalist IT Group weblog.

Since the start of the development of JDK 7, there is quite some discussion on the API’s in the standard Java libraries which covers date and time. In the current Java version (1.6) there are roughly three major (groups of) classes which are responsible for handling date and time: Date and Calendar, the formatting classes, and the classes in the java.sql package, including java.sql.Date, java.sql.Time and java.sql.Timestamp. Most developers agree that these classes are far from perfect.

In order to resolve this issue, JSR-310 is started to improve the date and time API in the standard Java libraries. However, due to lack of developers and slow progress, it became very uncertain if the JSR would be ready for inclusion in JDK 7 (which will eventually become Java 7, the name I will use in the rest of this article). JSR-310 is lead by Stephan Colebourne and Michael Nascimento Santos. Colebourne is the original author of the increasingly popular Joda Time project, which is a replacement for the default Java date and time API’s. At Devoxx 2009, taking place last November, Mark Reinhold of Sun announced that Java 7 will be delayed until September 2010 at the earliest. Stephan Colebourne sees this as a opportunity to release at least a partially complete JSR-310 in time for the upcoming Java release.

But why is the current Java date and time API broken? How can you circumvent the issues in this API? And how does JSR-310 intends to resolve the issues in the upcoming release? These questions I will try to answer in this article.

Current date and time API in Java

While it is a bit to much to explain the complete workings of the date and time API in Java 1.6 (and before), I will try to explain the main problems with the current date and time API in Java. I assume some upfront knowledge of the API by the reader, but probably it is not very difficult to follow for people who don’t have extensive experience with the API.

The Java 1.6 standard library contains a few classes which deals with date and time. The most important ones are Date and Calendar. Almost the entire API is designed around these two classes. The main problem with them is that fairly simple operations on date and time require a rather large amount of code with many instances of individual classes. This has a negative impact on performance. The API is inconsistent and confusing for developers, making code using Date and Calendar hard to read and maintain. Additionally, the API is incomplete which force developers to create custom solutions for simple problems. Finally, the API misses opportunities which would made the usage of the API simpler. With this last point, I mainly refer to the lack of fluent API’s and the fact that all objects are mutable.

In the current API only a specific instance in time can be represented using a Date object. This object represents a specific point in time, internally defined by the number of milliseconds since the Epoch (January the 1st 1970 at 0:00 hour) and a timezone. In fact, this could be easily represented by an immutable object. Unfortunately, this is not the case. In earlier Java versions, many methods were added to the Date class making it possible to manipulate it. Nowadays, almost all these methods are deprecated and should not be used anymore. However, they still exists, and worse of all the setTime(long time) method is not deprecated and changes the state of a Date object.

The fact that Date is a mutable object, makes it hard to use it in other classes which are immutable. One should always make a defensive copy of every Date object that is part of an immutable object. Joshua Bloch gives an example in his book Effective Java:

public final class Period {
  private final Date start;
  private final Date end;
  
  public Period(Date start, Date end) {
    if (start.compareTo(end) > 0)
      throw new IllegalArgumentException(start + " after " + end);
    this.start = start;
    this.end = end;
  }
  
  public Date start() {
    return start;
  }
  
  public Date end() {
    return end;
  }
}

Objects of the type Period appears to be immutable, however it is not due to the usage of the Date class. An example where a Period object is changed:

Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
end.setYear(78); // Modifies internals of P!

This bug makes it possible to change the end date of the Period p, which renders the check in the constructor of Period void. Of course, there is a pretty simple way to prevent this problem by making a copy of start and end in the constructor of Period:

public period(Date start, Date end) {
  this.start = new Date(start.getTime());
  this.end = new Date(end.getTime());
  [...] // remainder omitted
}

However, this requires additional effort of the user of the API and can easily be forgotten. When Date objects would be immutable, this extra copy would not be necessary.

The other class in the date and time API in Java is the Calendar class. Instances of this class represents a point at a specific type of calendar (most of the time Gregorian) and provide methods to do some simple calculations. The main problem with this class is that it is mutable as well. The methods on this class are also not very beautiful. For example, to get the current year of the Calendar instance cal, one should call cal.get(YEAR) where YEAR is a constant. It is also confusing that a Calendar can operate in two modes, namely ‘lenient’ and ‘non-lenient’. In the first case, it is possible to define values for fields which are normally out of range. For example, it is possible to set the month to 15. The Calendar object then automatically converts it to a valid month, by increasing the year by one, and set the month to april.
Wait, april I wrote? Yes, months are zero-based in the Calendar (however, days, years, etc. are not).
The way the days of a week are represented are a little bit confusion

The main problems are clear now, however, there are many other smaller problems. For example, there also exists java.sql.Date, java.sql.Time and java.sql.Timestamp. These classes are childs of the java.util.Date class, but add some functionality for use in databases. However, there is a problem in the implementation of these classes. The java.sql.Date class and is used to represent a date without a time, while the java.sql.Time class represents a time without a date. Timestamp adds nanoseconds to the Date object. However, internally they still contain both a time and date and the implementers did not override the equals and hashCode methods causing hard to find bugs:

Date date = new Date();
Time time = new Time(date.getTime());
java.sql.Date sqldate = new java.sql.Date(date.getTime());
Timestamp timestamp = new Timestamp(date.getTime());

System.out.println(date.toString()); // Sun Dec 20 15:53:55 CET 2009
System.out.println(time.toString()); // 15:53:55
System.out.println(sqldate.toString()); // 2009-12-20
System.out.println(timestamp.equals(date)); // false
System.out.println(date.equals(timestamp)); // true

This means that java.sql.Timestamp does not obey to the equals contract, saying that the equals should be symmetric. Additionally, it is confusing that Time and java.sql.Date only represent a part of the date, but still use the same equals implementation.

Astronomical Clock

Astronomical Clock


There are more problems with the current API. For example, there is no way to define durations or a reliable way to represent a date without a time, or a time without a date. The performance of the API is unpredictable, because the fields are recalculated at unexpected moments. Finally, it is not very straightforward to format a date for print. One should use the (Simple)DateFormat classes for this, which means additional objects.

Joda Time

At this moment there is already a working solution for the problems described in the previous section. It’s called Joda Time and this is a replacement for the date and time API in the Java standard library. Joda Time solves most problems that currently exists. Joda Time contains two ways of defining a particular date or time: instant for a particular point in the ‘date time continuum’ and partial for a time or date representation which is not exactly a point in time, because a part is missing (the time, timezone, year, etc.).

Intstants in Joda Time are defined by the ReadableInstant interface, of which the most used implementation the DateTime class is. A DateTime object is immutable and contains a fluent API to do calculations on it (which of course return new objects). In order to make it easy to use it in existing projects, it is easy to convert a JDK Date object to a DateTime object and vice versa. Joda Time also provides a mutable version of the DateTime class, MutableDateTime, which can be used when a lot of transformation on a date has to be done. However, the usage of this object is most of the time not really necessary and should be avoided in my opinion. A MutableDateTime can easily be converted to a immutable version of it.

Partials are represented by the ReadablePartial interface, of which the most used implementations are LocalDate, LocalTime and LocalDateTime. Object of these types are also immutable and can easily be converted to DateTime objects and JDK Date objects. Additionally, Joda Time contains Duration, Period and Interval for completeness.

Of course, an example of Joda Time usage cannot be omitted in this article:

DateTime now = new DateTime();
Period sixdays = new Period(0, 0, 0, 6, 6, 0, 0, 0);
System.out.println(now); // 2009-12-20T18:35:53.360+01:00
DateTime future = now.plus(sixdays);
System.out.println(future); // 2009-12-27T00:41:59.097+01:00
System.out.println(now.withYear(2028).plusDays(31).toString("dd-MM-yyyy hh:mm")); // 20-01-2029 06:41

This example initializes now to the current time (the default value of a DateTime without constructor parameters). The variable sixdays contains a reference to a Period object which defines a period of 6 days and 6 hours. Periods can easily be added to a DateTime object using the plus() method. Note that the result of the method should be assigned to a variable, since it does not modify the existing object, but creates a new one which has to be assigned to a variable in order to use it actually.
The last line shows how easy it is to perform simple calculations with date using Joda Time. Additionally, it shows another feature of Joda Time, namely the ease to format a date according to a specific pattern. A similar operation would be much more difficult using the JDK Date and Calendar classes, since one would have to instanciate a Calendar, Date, SimpleDateFormat and call several individual methods.

Joda Time also makes many other use cases very simple. For example, the DateTime constructor accept many different types of objects for initialization. For example, one can provide many different formatted String objects, which are automatically parsed correctly. This includes the ISO 8601 format, which is used in XML. For testing purposes Joda Time also makes it possible to change the current time, using DateTimeUtils.setCurrentMillisFixed(millis);.

JSR-310 and Joda Time

As mentioned earlier, JSR-310 is lead by Stephan Colebourne, who also created Joda Time. It may be obvious to take the latest Joda Time release and put a JSR stamp on it, declaring it the reference implementation. This is not what is happening, with good reason.
Stephan devoted a recent blog post on this topic, explaining why JSR-310 differs from Joda Time. The main reason is that Joda Time is not perfect.
The design goals for JSR-310 are clearly defined: The API should support immutability, a fluent API, it has to be extensible and the API should be clear, explicit and expected. Especially this last point is where Joda Time is not perfect. For example, Joda Time uses the notion of Chronology to represent different calendar types. It is possible to define the Chronology when instantiating a DateTime object. In the default case, a DateTime object will return a value between 1 and 12 when calling the getMonthOfDay() method. However, when using a for examle a Coptic Chronology, this method can also return 13, since the Coptic calendar has 13 months. This makes the API return values the user might not expect, and in fact, the previous method call requires a check to make sure the result is as expected. Also the use of the ReadableInstant by DateTime and the Instant class (which is a machine representation of an instant in time) is wrong, since there is difference in how humans define an instant in time compared to how machines see it. Finally, Joda Time accept null values in many places without throwing an error, which is also wrong according to Colebourne.

The issues in Joda Time should be fixed in the JSR-310 implementation making it an even better date and time API. Should we therefor not use Joda Time? Definitely not! Of all available options, Joda Time is definitely the best choice for working with dates and times in Java. The fact that the completion of JSR-310 takes a very long time, is since for most developers Joda Time fixes the problem that exists in the current JDK API, making the urgency of completing JSR-310 pretty low.

Conclusion

The date and time function in the default Java SDK is flawed in many ways. While it can be used for most projects with some extra effort, it can also cause many unexpected problems. JSR-310 is on its way to finally fix this problem. However, it is still not yet sure if it will be part of Java 7, mainly because of the lack of developers.
For new projects, there is very few arguments for not using Joda Time. It is well tested and well supported, including support for Hibernate and JSP’s. It makes it a lot easier to perform calculations using dates, and provides an easy to use API with reliable performance.

Tags: , ,

12 Responses to “Java Date and Time API and JSR-310”

  1. January 8th, 2010 at 4:07

    Jonathan Felch says:

    Joda Time is a great, and as you say very popular, alternative to Calendar and Date. That said, there are lots of problems with Joda Time and JSR-310 that are serious enough than fans of these initiatives should push for serious work and reconsideration before it moves closer to any JDK release. Some considerations might include:

    1. From a library point of view, the package is just too big. Interval and period has similar but incomputable and awkward interfaces. Except for DateMidnight there are few ways of initiating a time instance that represents the beginning of a period around a given reference date. Rather than sub-classing ReadableDate, there should probably just be simple factory methods to get the start or end of a period around a given reference date. All said, the library needs a design overhaul and should be a lot smaller.

    2. Financial dates. Any serious revision to dates and times in Java should include simple implementations for calculating business and financial accrual (number of days of interest payable on a debt) using ISO standard day count conventions and the like. Similarly there should be basic support for business and legal calendars used by the countries where most software development is done (U.S, E.U., Russia, China, India, etc…)

    3.) Date serialization and portability. Joda Time, Calendar, and Date all use context from the local machine to initialize the TimeZone and initializing all the fields in Calendar is extremely expensive. The date / calendar should have a small enough footprint to exist in a cluster and get serialized around the network as part of a time series collection in which hundreds of thousands and millions of observations can be organized temporally without a huge I/O or computational foot print. Contact Alex Miller or any of the guys at Terracotta and ask them what they want in a Date class. Of all the standard classes in the JDK, the Date/Calendar/JodaTime problem was probably the most common, most expensive, and most annoying part of clustering terrabytes of data on a networked heap.

  2. January 9th, 2010 at 1:10

    Martin Sturm says:

    Thanks for your comment. I think your points are valid, and some of them should maybe addressed in JSR-310. I’m not sure if I understand your first point. You say the library is too big, but when is a library too big? If the modularization effort in Java 7 will be finished, it is theoretically possible to split the date/time handling into several sub-packages. For example, it will be possible to put financial dates into a seperate package, and as such I don’t think it should be part of the ‘core’ JSR-310 package (I think Stephen Colebourne mentioned this also in a blog post). With regard to your last point: to be honest, I don’t have enough knowledge to say something meaningful on clustering. I think it is also a difficult trade of, since many times users of the library expect the package to use the default timezone for the local machine, but I can imagine that this is a problem when clustering or a class is (de)serialized.

  3. January 9th, 2010 at 19:26

    Anthony says:

    Financial Dates? Don’t go there… That is a huge nut to crack that is beyond the scope of a well thought out Date/Time implementation. We need a better solution to Date/Time in Java than Date/Calendar, and we can build a decent solution for Financial Dates on top of a smart implementation. My favorite solution is http://objectlabkit.sourceforge.net/

    Java is overall a pretty smart and well thought out language with smartly constructed libraries, but I am amazed at how poor their Time/Date solution is compared to other languages. Joda time is a decent solution that has been thoroughly tested over years… I don’t see why we don’t want to leverage this and build it into the Java core. It is a long time coming.

    I need this part of the JDK (rather than using Joda-Time) so that other standards can leverage it, like JPA, Bean Validation, JSF, etc.

    I don’t understand the “lack of developers” comment… Why does it need more developers? Joda-Time provided the perfect reference implementation, so this spec was largely written already, so you didn’t need a lot of developers to get involved. Certainly, we need people to review and ratify it, but I suspect that all of the joda-time users would welcome it.

  4. January 10th, 2010 at 5:40

    i30817 says:

    The other class in the date and time API in Java is the Calendar class. Instances of this class represents a point at a specific type of calendar (most of the time Gregorian) and provide methods to do some simple calculations. The main problem with this class is that it is immutable as well.

    Did you mean mutable?

  5. January 10th, 2010 at 5:58

    i30817 says:

    Actually i like that there is a large api as long as:

    1) it has a factory class (like Executors)
    2) exposed in interfaces (for extension factories)
    3) (i would say private implementations, however that is not friendly to extensions, so extensions in another sub-package)

    (serialization can be optimized by readObject writeObject methods).

  6. January 10th, 2010 at 12:18

    Martin Sturm says:

    Yes, I meant mutable. Thanks for pointing out!

  7. January 19th, 2010 at 14:08

    Frank Hardisty says:

    I’m in the camp that hopes JSR 310 makes it in. It’s time for time!

    Joda Time is nice, it has a good API and seems well implemented. However, an external library is always in danger of falling behind (Apache Commons Collections, anyone?), or getting pushed aside later by a new standard.

    Also, the size of the 1.6 joda-time.jar is 534 kB. Now, half a megabyte ain’t no thing on the server, but if you want to include it in a client application (Web Start or applet), that’s a fair bit of bloat just to do some reasonable date and time operations.

  8. January 19th, 2010 at 20:03

    Tom says:

    I don’t think the comments in the sample Joda code represent the correct output. I get (of course the current time is different):

    2010-01-19T12:56:09.256-06:00
    2010-01-25T18:56:09.256-06:00
    19-02-2028 12:56

    The minutes, seconds, and milliseconds shouldn’t change between the first two lines.

  9. February 15th, 2010 at 16:38

    Chris Winters says:

    Another benefit of Joda (and presumably JSR-310) is that everything is threadsafe. Stressing immutability goes a long way toward this, but the fact that the JDK SimpleDateFormat is *not* threadsafe has bitten quite a few people.

  10. March 28th, 2010 at 17:51

    gustav says:

    JSR-310 is just one of many projects that is more or less failing due to lack of resources.
    So will oracle bring resources to JDK development or not ?.
    Its not much point of keep going if not, this problem has been going on for many years and its only been worsening over time.
    The alternative is to let the needed control go, and let outsiders do alot more.

  11. June 10th, 2010 at 16:12

    domik.ch says:

    You can get current date and/or time in Java using the following method. You may change the date format in the constructor of SimpleDateFormat to get the result in a different format:
    import java.util.Date;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;

    private String getDateTime() {
    DateFormat dateFormat = new SimpleDateFormat(“yyyy/MM/dd HH:mm:ss”);
    Date date = new Date();
    return dateFormat.format(date);
    }

  12. January 12th, 2013 at 17:34

    Welcome to Java7 Quick tour | IT Student Blog says:

    […] some Java 7 attention (even if it’s not the overhaul  many of us had hoped […]