Sunday, April 24, 2016

No Time Zone in java.util.Date



We can change the time zone of the local machine by changing the default timezone of the JVM like below.

TimeZone.setDefault(TimeZone.getTimeZone("NEW_TIME_ZONE");

A java.util.Date has no time zone†. It represents UTC/GMT (no time zone offset). Very confusing because its toString method applies the JVM's default time zone when generating a String representation.

Avoid j.u.Date

For this and many other reasons, you should avoid using the built-in java.util.Date & .Calendar & java.text.SimpleDateFormat. They are notoriously troublesome.

Instead use the java.time package bundled with Java 8. These new classes are inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project. For Java 6 & 7, use the back-port project, ThreeTen-Backport. For Android, the adaptation of that back-port, ThreeTenABP. See Oracle Tutorial.
java.time

The java.time classes can represent a moment on the timeline in three ways:

  • UTC (Instant)
  • With an offset (OffsetDateTime with ZoneOffset)
  • With a time zone (ZonedDateTime with ZoneId)


Instant

In java.time, the basic building block is Instant, a moment on the time line in UTC. Use Instantobjects for much of your business logic.Instant instant = Instant.now();

OffsetDateTime

Apply an offset-from-UTC to adjust into some locality’s wall-clock time.

Apply a ZoneOffset to get an OffsetDateTime.ZoneOffset zoneOffset = ZoneOffset.of( "-04:00" ); OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );

ZonedDateTime

Better is to apply a time zone, an offset plus the rules for handling anomalies such as Daylight Saving Time (DST).

Apply a ZoneId to an Instant to get a ZonedDateTime. Always specify a proper time zone name. Never use 3-4 abbreviations such as EST or IST that are neither unique nor standardized.ZoneId zoneId = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Formatted Strings

Call the toString method on any of these three classes to generate a String representing the date-time value in standard ISO 8601 format. The ZonedDateTime class extends standard format by appending the name of the time zone in brackets.

String outputInstant = instant.toString(); // Ex: 2011-12-03T10:15:30Z 
String outputOdt = odt.toString(); // Ex: 2007-12-03T10:15:30+01:00 
String outputZdt = zdt.toString(); // Ex: 2007-12-03T10:15:30+01:00[Europe/Paris]


For other formats use the DateTimeFormatter class. Generally best to let that class generate localized formats using the user’s expected human language and cultural norms. Or you can specify a particular format.
Joda-Time

While Joda-Time is still actively maintained, its makers have told us to migrate to java.time as soon as is convenient. I leave this section intact as a reference, but I suggest using the java.time section above instead.

In Joda-Time, a date-time object (DateTime) truly does know its assigned time zone. That means an offset from UTC and the rules and history of that time zone’s Daylight Saving Time (DST) and other such anomalies.

String input = "2014-01-02T03:04:05"; 
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" ); 
DateTime dateTimeIndia = new DateTime( input, timeZone ); 
DateTime dateTimeUtcGmt = dateTimeIndia.withZone( DateTimeZone.UTC );


Call the toString method to generate a String in ISO 8601 format.String output = dateTimeIndia.toString();


Joda-Time also offers rich capabilities for generating all kinds of other String formats.

If required, you can convert from Joda-Time DateTime to a java.util.Date.Java.util.Date date = dateTimeIndia.toDate();


Search StackOverflow for "joda date" to find many more examples, some quite detailed.