Joda-Time?

We generally prefer to use the Joda-Time library to handle date and time data.

  • Manipulation methods: plusHours, plusDays etc
  • Immutable objects available
  • Specific classes for partial representations (LocalDate, LocalTime etc)
  • Thread-safe parser-formatters
  • Simple toString/parse conversions to/from ISO strings

DateTime

Most introductions and snippets about Joda-Time illustrate the core DateTime class, which combines a date, time and timezone.

DateTime now = new DateTime(2015, 4, 13, 9, 15, 0); // use default timezone
DateTime laterToday = now.withTime(17, 30, 0, 0);
DateTime tomorrow = now.plusDays(1);
DateTime muchLater = now.plusMonths(6);

Date + Time + Timezone ⇌ Instant (epoch millis)

Traps

Date + Time + Timezone ⇌ Instant (epoch millis)

except when it isn't

What is the corresponding instant to 2015-03-29T01:30:00 in Europe/London timezone?

How about 2015-10-25T01:30:00 ?

Parsed strings as constants

DateTime dt = new DateTime(2014, 12, 31, 11, 24, 15); // Europe/London
// dt.toString()  : "2014-12-31T11:24:15.000Z"
DateTime dt2 = DateTime.parse("2014-12-31T11:24:15Z");
// dt2.toString() : "2014-12-31T11:24:15.000Z"
DateTime dt = new DateTime(2015, 4, 13, 9, 15, 0); // Europe/London
// dt.toString()  : "2015-04-13T09:15:00.000+01:00"
DateTime dt2 = DateTime.parse("2015-04-13T09:15:00+01:00");
// dt2.toString()  : "2015-04-13T09:15:00.000+01:00"

DateTime equality

assertThat(new DateTime(2008, 6, 1, 14, 0, 0) /* Europe/London */,
    equalTo(DateTime.parse("2008-06-01T14:00:00+01:00")));
Expected: <2008-06-01T14:00:00.000+01:00>
     but: was <2008-06-01T14:00:00.000+01:00>

what

These DateTime instances do represent the same time instant, with the same time zone offset, but not the same time zone ruleset. Parsing a time with +01:00 or Z as a suffix resolves to a fixed-offset "time zone".

Unfortunately the ruleset isn't clearly indicated in the toString() output, so it's easy to miss the distinction.

Did you mean Instant?

There is in fact an org.joda.time.Instant class. This purely encapsulates an instant, free of any concept of timezone.

assertThat(new DateTime(2008, 6, 1, 14, 0, 0).toInstant(),
    equalTo(Instant.parse("2008-06-01T14:00:00+01:00")));

This is likely a more suitable type to correspond to timestamps in databases, event structures...

Problems

Instant does not have those oh-so-convenient plusDays, plusHours etc methods. You have to convert to DateTime to do that sort of manipulation. This pushes you to supply a timezone context.

Instant will be formatted as UTC by a DateTimeFormatter unless that formatter has an override zone. Arguably not a bad thing, but not what I expected.

JSR-310: java.time

Also has Instant, and emphasises separation of machine-timeline with human date/times more strictly.

DateTime becomes ZonedDateTime and/or OffsetDateTime, emphasising what they contain.

ZonedDateTime includes the time zone ruleset name in its toString() if it is not a fixed offset.

As per Colebourne's blog entry, DateTime implementing ReadableInstant has come to be seen as a mistake (#1 on the list).