outputting dates in RFC822 and ISO8601 formats


Okay, this is something else that is simple but generally requires to look at specs just to see how to do it properly. And these days, what with everyone generating RSS and such, creating properly formatted RFC822 and ISO 8601 dates is important to make sure the feeds validate. So here's the code, using Java's SimpleDateFormat, to output both formats properly.


import java.util.Date;
import java.text.SimpleDateFormat;

//... class definition here...

public static SimpleDateFormat ISO8601FORMAT
    = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
public static SimpleDateFormat RFC822DATEFORMAT
    = new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z", Locale.US);

public static String getDateAsRFC822String(Date date)
{
  return RFC822DATEFORMAT.format(date);
}

public static String getDateAsISO8601String(Date date)
{
  String result = ISO8601FORMAT.format(date);
  //convert YYYYMMDDTHH:mm:ss+HH00 into YYYYMMDDTHH:mm:ss+HH:00
  //- note the added colon for the Timezone
  result = result.substring(0, result.length()-2)
    + ":" + result.substring(result.length()-2);
  return result;
}


Later: Aside from some fixes due to comments (thanks!), Erik, via IM, notes that RFC 822 has been superseded by RFC 2822, in which years on dates use four digits rather than two. The RSS Spec actually encourages the use of four digits from RFC 2822 (even though it explicitly mentions RFC 822 only). So I modified the code for that.

Also, Zoe, via email, notes that a cleaner way of generating ISO 8601 dates is to use the UTC designator "Z", which has the added advantage of making dates easier to parse back in Java. Clearly this is a better solucion when possible, however, this means that all times have to be changed into UTC, something that might not be desirable in many cases where you want to maintain Timezone information. The parsing of an ISO 8601 date with the colon is similarly "dirty" by having to remove the ":" by hand before being able to parse it from Java.

Categories: soft.dev
Posted by diego on January 4 2005 at 2:26 PM
Comments (please see the comments & trackback policy).

Hmmm... regarding your ISO8601FORMAT... would not the time zone be formated wrongly?

The W3C profile of ISO 8601 says this:

1994-11-05T08:15:30-05:00

Note the colon in the time zone...

Neither 'Z' (aka 'rfc822timezone') nor 'z' (aka 'timezone') will produce such time zone format as far as I know...

Did I miss something?

Posted by: Zoe at January 4, 2005 3:53 PM

Another thing... you seems to be using a static Format instance... which will most likely create problems if you ever format anything from different threads...

Synchronization

Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html

Posted by: Zoe at January 4, 2005 3:57 PM


Not to be pedantic (well, okay I am), but the return value is String, there's no need to label the method as getXXXXString(), it's obvious that's what it's doing. Naming stuff that way makes the methods unweildy and leads to Hungarian Notation eventually.

:-)

-Russ

Posted by: Russ at January 4, 2005 4:42 PM

Zoe: you're absolutely right, I was writing it down from memory and I forgot that these was actually one of my pet peeves from Java, i.e., that it's not possible to generate directly the ISO 8601 date using the Simple Date Format patterns. I just added the necessary line.

Re: synchronization. Good point, and of course that is something to keep in mind when you use this.

Russ: good point as well... :)

Thanks!

Posted by: Diego at January 4, 2005 4:47 PM

I believe your ISO8601 format needs to include the '-' inbetween the year, month, and day. That is, "yyyy-MM-dd'T'HH:mm:ssZ".

Also, while the RFC822 format is correct, your code will generate localized names for the day and month. They need to be in English. The following would be correct:

import java.util.Locale;

// ...

public static SimpleDateFormat RFC822DATEFORMAT
= new SimpleDateFormat("EEE', 'dd' 'MMM' 'yy' 'HH:mm:ss' 'Z", Locale.US);

Posted by: David Czarnecki at January 4, 2005 7:34 PM

David: thanks. I checked my own code in various places and indeed I am using Locale.US for rfc822, as well as the dashes for ISO. I corrected both on the entry. This is the last time I write down standards-bound code from memory without checking the spec or my own code! :)

Posted by: Diego at January 4, 2005 8:03 PM

What about milliseconds in the date? For example, log4j formats dates as ISO8601 using ,nnn for the millisecond component. From what I can tell, .nnn is also valid.

Posted by: Krasna Halopti at January 4, 2005 11:04 PM

There's also the MailDateFormat in the JavaMail APIs to provide this formatter:

http://java.sun.com/products/javamail/1.3/docs/javadocs/javax/mail/internet/MailDateFormat.html

Posted by: Mark Derricutt at January 5, 2005 11:32 PM

Copyright © Diego Doval 2002-2007.
Powered by
Movable Type 3.35