Friday 20 November 2009

Why JSR-310 isn't Joda-Time

One question that has been repeatedly asked is why JSR-310 wasn't simply the same as Joda-Time. I hope to expain some reasons here.

Joda-Time as JSR-310?

At its heart, JSR-310 is an effort to add a quality date and time library to the JDK. So, since most people consider Joda-Time to be a quality library, why not include it directly in the JDK?

Well, there is one key reason - Joda-Time has design flaws.

Now before everyone panics and abuses that line as a tweet, I need to say that Joda-Time is by far the best option curently available, and that most users won't appreciate the design flaws. But, I do want to document them, so the basis for the changes in JSR-310 is clear.

1) Human/Machine timelines

One element of clarity is a better understanding of the distinction between the two principle views of the timeline - Human and Machine.

Machines have one view - a single, ever increasing number. In Java we set zero as 1970-01-01T00:00Z and count in milliseconds from there.

Humans have a totally different view of time. We have multiple calendar systems (one primary, many others), which divide the timeline into years, months, days, hours, minutes and seconds. In addition, humans have time zones which cause the values to vary around the globe, and for there to be gaps and overlaps in the human timeline as DST starts and ends.

Much of the time, a conversion between the two timeline views is possible with a time zone, however in a DST gap or overlap, things are much less clear.

Joda-Time defines two key interfaces - ReadableInstant and ReadablePartial. Both the Instant class (simple instant in time) and the DateTime class (human view of an instant in time) are implementations of ReadableInstant. This is wrong.

DateTime is a human-timeline view of the world, not a machine-timeline view. As such, DateTime is much better thought of, and designed as, a LocalDateTime and a timezone rather than the projection of the machine timeline onto the human timeline. Thus, DateTime should not implement ReadableInstant.

2) Pluggable chronology

What is the range of values returned by this method in Joda-Time?:
int month = dateTime.getMonthOfYear();
The answer is not 1 to 12, but could be 1 to 13! (yet January is still 1 and December is 12)

The answer to this puzzler is down to pluggable chronologies. Each date/time class in Joda-Time has a pluggable chronology. This defines the calendar system that is in use. But most users of the API never check to see if the chronology is the standard ISO/ chronology before calling getMonthOfYear(). Yet, the Coptic chronology has 13 months in a year, and thus can return a range of 1 to 13.

A better solution would be to keep the date/time classes restricted to a single calendar system. That way, the result from each method call is clear, and not dependent on any other state in the class, like the chronology.

3) Nulls

Joda-Time accepts null as a valid value in most of its methods. For date/times it means 1970-01-01T00:00Z. For durations it means zero. For peiods it means zero.

This approach causes random bugs if your code happens to provide a null to Joda-Time that you hadn't originally planned for. Instead of throwing an error, Joda-Time continues, and the resulting date/time is going to be different from what you want.

4) Internal implementation

Certain aspects of the internal implementation are complex, and the result of having pluggable chronologies and a misunderstanding of the machine/human divide in the timeline. Changing this is a big change to the code.

One particular area of trouble is managing DST overlaps. The behaviour in Joda-Time of these isn't that well defined.

Summary

Joda-Time isn't broken!

It does the job it was designed for, and does it much better than the JDK. And it is widely used and without too many major issues. However, after a few years, it is now clear where it could be designed better.

I took the decision that I didn't want to add an API to the JDK that had known design flaws. And the changes required weren't just minor. As a result, JSR-310 started from scratch, but with an API 'inspired by Joda-Time'.

I hope that explains the thought process behind the creation of a new API in JSR-310.

25 comments:

  1. Dmytro Vyazelenko20 November 2009 at 10:19

    Hi, Stephen!

    Thanks for the thorough explanation!

    I have just one question though: when JRS-310 will be finished and will become part of the JDK?! Since now JDK7 schedule is shifted is there any hope that this JSR will make it?

    Thanks,
    Dmytro

    ReplyDelete
  2. Real Question is, Now that Java7 (or JDK7, whatever the name)is delayed, can JSR-310 be included? NIO-2 cleaned the File mess, why not letting the JSR 310 clean the Date-Calendar mess once and for all.

    ReplyDelete
  3. Have a look at this message:

    https://jsr-310.dev.java.net/servlets/ReadMsg?list=dev&msgNo=1389

    It looks like JSR 310 needs some manpower to get to the finish line.

    ReplyDelete
  4. I think the bigger question is whether there's any forward movement on JSR-310. My firm started doing work based on it, and was willing to contribute, but there've not been any SVN commits in months, and no activity on the mailing lists at all.

    We're more than willing to help with the effort, but we can't really LEAD the effort.

    Is JSR-310 really still alive or not is the bigger question to me.

    ReplyDelete
  5. Per your point #2, does that mean there won't be chronologies in JSR-310?

    ReplyDelete
  6. A more important question to me - and one I've never seen raised - is how is JSR 310 going to mesh with units and measurements (JSR 275)?

    I'm an avid user of weights and measurements currently (through JScience), and while there's not a simple way to mix a Joda-time based framework with units and measurements, it is something that needs to be carefully considered.

    While it adds complexity to the design decisions of JSR 310, I think both proposals would be stronger if they were interoperable.

    Otherwise, I think we'll instantly regret having dual and incompatible representations of durations, hours, minutes, seconds, etc.

    ReplyDelete
  7. The real question is why not fork Joda-Time? Surely it must be easier to update unit tests and refactor the code base than write it from scratch..

    ReplyDelete
  8. Per James point about forking Joda time, would the JSR 275 proposal be flexible enough that an SPI could be built off a fork of Joda time?

    ReplyDelete
  9. For clarity's sake, "James" != "James Grahn" (in this case).

    And I'm not certain I follow your question, Alan. SPI?

    ReplyDelete
  10. The question is: do we need JSR-310?

    Just another standard without any movement which, maybe around JDK 1.9 will make it into classpath.

    ReplyDelete
  11. Firstly a big thanks to you Stephen for all your work and effort.

    I believe there is huge number of java developers who would love to see this JSR get to completion - and become an official/blessed replacement for java.util.Date/Calendar.

    The delay of JDK7 is a real opportunity to finish this JSR and get it into the JDK. Is it possible to get a list of what you consider to be the outstanding tasks?

    Fantastic work, I'm sure the community can help to get the job done.

    Cheers, Rob.

    ReplyDelete
  12. Stephen Colebourne22 November 2009 at 23:39

    All, I expect to clarify the position around JSR-310 in the next few days.

    ReplyDelete
  13. Question about your first point 1 - Human/Machine timelines

    The whole question is that you defined DateTime as Human view of an instant in time. What if DateTime is defined as Machine View?

    Then, your whole argument is not valid. Could it because you misunderstand it?

    ReplyDelete
  14. Much like the original JDK designers, you're trying to solve too big a problem.

    99.9% of the software in the world has to deal with a small of date/time functionality that revolves around (a) machine times and (b) gregorian calendar times in various timezones.

    There is an incredibly small set of people who need more complicated libraries for other calendars and historical stuff and other complex representations of "date" and "time".

    But those should be 2 completely separate libraries, so that the bulk of us are not burdened by unnecessary complexity.

    ReplyDelete
  15. @rob: i dont think that comunity did a great job so far for JSR 310.

    ReplyDelete
  16. @Noel: Even machine time is complicated by leap seconds (either treat them properly, or shut down your system for a few hours when they happen).

    History also creeps in in unexpected places. For example many applications will have (possibly implicit) references to 1970-01-01. Unfortunately this is a special case date in the UK --- the timezone offset was +1:00 and not the 0:00 that most people might expect.

    ReplyDelete
  17. Joda Time don't know which day of the week is regarded as the first day of the week, given some Locale. I find this unacceptable in regard to displaying a calendar to a user.

    http://stackoverflow.com/questions/1801907/joda-time-first-day-of-week

    ReplyDelete
    Replies
    1. Another flaw is missing concept of work days vs. holidays. ICU4J while it remains closer to the old JDK Date/Calendar has massively improved, and some of that went into JDK. As a vast majority of businesses and calculations require the concept of at least something like "isWorkDay()" or similar, missing that is a serious bug in JSR 310. JodaTime didn't have that either, there was however some class or interface I can't recall to extend, which hasn't found its way into the JSR so far unfortunately.

      Delete
    2. How do you define a work-day?

      Let's say I work in a hot-dog stall, and I ask my calendar if Sunday is a work-day. What should it answer?

      Delete
  18. Hi
    I'm starting a new project and came across this blog entry because i'm choosing now which date library to use. First, thanks to this post.. but i must say that i do not agree with what you said to be design flaws in joda-time (or i completely miss the point!). What you called human and machine timelines are just two views of the same thing : the timeline. Like in MVC : one model, but multiple views. One timeline, but multiple views : "human" view, "machine" view. But i agree when you say that a DateTime should not implement ReadableInstant, because it's not an instant ; it **has** an instant.
    just my +1

    Hermann

    ReplyDelete
  19. Learned a lot about how date and time are viewed, this human/machine was totally new to me.

    ReplyDelete
  20. +1 for your effort and knowing your limitations.

    Maybe good enough is not an option for a system-wide language library.

    ReplyDelete
  21. Joda was a quality piece of software far superior to what Java provided. JSR-310 is an evolution - credit to Stephen for his ability to self-analyse and improve. I doubt any critic could possibly provide a better library.

    ReplyDelete
  22. Uh did you mean to use getMonthOfYear()? I'm confused by getMonthOfDay().

    ReplyDelete
  23. Did you mean 'getMonthOfYear()' in the sentence instead of 'getMonthOfDay()'
    But most users of the API never check to see if the chronology is the standard ISO/ chronology before calling getMonthOfDay()

    ReplyDelete

Please be aware that by commenting you provide consent to associate your selected profile with your comment. Long comments or those with excessive links may be deleted by Blogger (not me!). All spam will be deleted.