Parsing dates using a set format in Java SE

By: on October 31, 2007

Tony mentioned a while back the parlous state of Java’s standard time libraries, and I wish I’d remembered before now, because he also pointed to Joda-time, which on the strength of a brief scan seems to me a compelling replacement. Hindsight, &c.

But to the matter at hand: getting a sensible result out of Java’s provisions for date parsing. Specifically, parsing a particular format, rather than a locale-dependent format. The stock way to do this is to use java.text.SimpleDateFormat.parse() with a suitable format string, say "dd MMM yyyy", which gives you a java.util.Date. The trouble starts when you want it to do what you mean; in my case, for 3 Oct 2007 to give you midnight on the 3rd of October 2007 UTC (there’s nothing in Java that represents an interval, so we have to settle for representative instants, and we can’t rely on things like databases to cope with timezones). Why doesn’t this work?

Because of the programmer’s friend the timezone. SimpleDateFormat assumes, if it’s not told, that what it’s parsing is in the system timezone, so in London the string from before is interpreted as midnight on the 3rd of October, British Summer Time; i.e., eleven at night on the 2nd, UTC. That’s not a bad assumption, although I didn’t see it documented anywhere, and fits well with the rest of the formatting APIs and locales and so on. The problem is that there’s no way to stop it behaving like that.

There are some teases, though: for example, java.text.DateFormat.setTimeZone() sounds like it will do what I want; but sadly, it only counts for formatting and not for parsing.

So, to the payoff: The expedient way to “neutralise” a date is to simply apply the system timezone offset and daylight savings offset to the parse result, then assert that it’s UTC.

import java.text.*;
import java.util.*;

public class UTCParse {
    public static void main(String[] args) {
    SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy");
 SimpleTimeZone utc = new SimpleTimeZone(0, "UTC");
  Calendar c = new GregorianCalendar(); // this picks up the system timezone
  try {
       Date d = sdf.parse(args[0]); // this assumes the system timezone
        c.setTimeInMillis(d.getTime());
     if (args.length > 1 && "utc".equals(args[1])) {
                // normalise the value
       c.setTimeInMillis(c.getTimeInMillis() +
                                        c.get(Calendar.ZONE_OFFSET) + 
                                        c.get(Calendar.DST_OFFSET));
       }

       SimpleDateFormat outformat = new SimpleDateFormat("dd MMM yyyy HH:mm Z");
       outformat.setTimeZone(utc);
     System.out.println(outformat.format(new Date(c.getTimeInMillis())));
    }
   catch (ParseException e) {
      System.out.println("Try a date formatted dd MMM yyyy");
 }
    }
}
FacebookTwitterGoogle+

2 Comments

  1. scoutice says:

    thanks a lot for this valuable hint for me

  2. Gubbi says:

    Another alternative would be:

    SimpleDateFormat timeFormatter = new SimpleDateFormat(“hh:mm:ss”);
    timeFormatter.setCalendar(Calendar.getInstance(TimeZone.getTimeZone(“UTC”)));
    System.out.println(timeFormatter.parse(“08:00:00.0000000″));

Post a comment

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>