We generally prefer to use Joda-Time for our date and time representation. Its immutable objects fit our house style, and the plusHours, plusDays etc methods usually produce much more readable and maintainable code than the giant bag of static methods based on Date and Calendar that we had before. Throw in easy construction from components, thread-safe parsers and formatters, a richer type catalogue for representing date-only, time-only, timezone-less values and integrated conversion to/from ISO-style strings, and working with date and time values becomes more comfortable and less fragile.
This snippet is fairly typical:
DateTime now = new DateTime(2015, 4, 13, 9, 15 /*default timezone*/); DateTime laterToday = now.withTime(17, 30, 0, 0); DateTime tomorrow = now.plusDays(1); DateTime muchLater = now.plusMonths(6);
In principle, a DateTime contains a date, a time and a timezone. These three correspond to an instant- a number of milliseconds since the epoch, 1st Jan 1970 00:00 UTC.
Actually, that’s not quite correct- there are some date/time/timezone combinations that don’t correspond to an instant, and some that ambiguously reference multiple instants. This occurs when the timezone includes rules for daylight savings time, producing gaps where the clocks go forward and overlaps when the clocks go back. (Consider how you would interpret “2015-03-29T01:30:00” as London time, or “2015-10-25T01:30:00”).
Here’s a nasty thing that can occur when you use DateTime, though. If you wrote this:
assertThat(new DateTime(2008, 6, 1, 14, 0, 0) /* Europe/London */, equalTo(DateTime.parse("2008-06-01T14:00:00+01:00")));
Then (if your system timezone is “Europe/London”, or you explicitly passed it in as the parameter) you would get this highly unhelpful failure:
Expected: <2008-06-01T14:00:00.000+01:00> but: was <2008-06-01T14:00:00.000+01:00>