Parsing RFC 2822 date in JAVA

16.5k views Asked by At

I need to parse an RFC 2822 string representation of a date in Java. An example string is here:

Sat, 13 Mar 2010 11:29:05 -0800

It looks pretty nasty so I wanted to make sure I was doing everything right and would run into weird problems later with the date being interpreted wrong either through AM-PM/Military time problems, UTC time problems, problems I don't anticipate, etc...

Thanks!

7

There are 7 answers

2
Buhake Sindi On BEST ANSWER

This is quick code that does what you ask (using SimpleDateFormat)

String rfcDate = "Sat, 13 Mar 2010 11:29:05 -0800";
String pattern = "EEE, dd MMM yyyy HH:mm:ss Z";
SimpleDateFormat format = new SimpleDateFormat(pattern);
Date javaDate = format.parse(rfcDate);

//Done.

PS. I've not dealt with exceptions and concurrency here (as SimpleDateFormat is not synchronized when parsing date).

0
Arvind Kumar Avinash On

RFC 2822 date-time string contains timezone offset e.g. the given string Sat, 13 Mar 2010 11:29:05 -0800 has a timezone offset of -08:00 hours from UTC i.e. the equivalent date-time at UTC can be obtained by adding 8 hours to Sat, 13 Mar 2010 11:29:05.

java.time

The modern date-time API API has OffsetDateTime to represent a date-time with timezone offset.

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

class Main {
    public static void main(String[] args) {
        String strRFC2822DateTimeStr = "Sat, 13 Mar 2010 11:29:05 -0800";

        OffsetDateTime odt = OffsetDateTime.parse(strRFC2822DateTimeStr, DateTimeFormatter.RFC_1123_DATE_TIME);
        System.out.println(odt);

        // Alternatively: using a custom DateTimeFormatter
        DateTimeFormatter parser = DateTimeFormatter.ofPattern("EEE, dd MMM uuuu HH:mm:ss XX", Locale.ENGLISH);
        System.out.println(OffsetDateTime.parse(strRFC2822DateTimeStr, parser));

        // In case you need the equivalent date-time at UTC
        OffsetDateTime odtUtc = odt.withOffsetSameInstant(ZoneOffset.UTC);
        System.out.println(odtUtc);
    }
}

Output:

2010-03-13T11:29:05-08:00
2010-03-13T11:29:05-08:00
2010-03-13T19:29:05Z

Learn more about the modern Date-Time API from Trail: Date Time.

Some useful links:

  1. Never use SimpleDateFormat or DateTimeFormatter without a Locale.
  2. You can use y instead of u but I prefer u to y.
  3. How to use OffsetDateTime with JDBC.
2
Serhii D On

Try this:

String dateTime = OffsetDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME); 
//RFC_1123 == RFC_2822
1
pathfinder78 On

DateTimeFormatter.RFC_1123_DATE_TIME

Since Java 8 new datetime classes were implemented: java.time.ZonedDateTime and java.time.LocalDateTime. ZonedDateTime supports the parsing of RFC strings nearly out of the box:

String rfcDate = "Tue, 4 Dec 2018 17:37:31 +0100 (CET)";  
if (rfcDate.matches(".*[ ]\\(\\w\\w\\w\\)$")) {
    //Brackets with time zone are added sometimes, for example by JavaMail
    //This must be removed before parsing
    //from: "Tue, 4 Dec 2018 17:37:31 +0100 (CET)"
    //  to: "Tue, 4 Dec 2018 17:37:31 +0100"
    rfcDate = rfcDate.substring(0, rfcDate.length() - 6);
}

//and now parsing... 
DateTimeFormatter dateFormat = DateTimeFormatter.RFC_1123_DATE_TIME;
try {
    ZonedDateTime zoned = ZonedDateTime.parse(rfcDate, dateFormat);
    LocalDateTime local = zoned.toLocalDateTime();        
} catch (DateTimeParseException e) { ... }
4
Laurent VB On

If your application is using another language than English, you may want to force the locale for the date parsing/formatting by using an alternate SimpleDateFormat constructor:

String pattern = "EEE, dd MMM yyyy HH:mm:ss Z";
SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.ENGLISH);
2
Casper On

Please keep in mind that the [day-of-week ","] is optional in RFC-2822, hence the suggested examples are not covering all RFC-2822 date formats. Additional, the RFC-822 date type allowed many different time zone notations(obs-zone), which are not covered by the "Z" format specifier.

I guess there is no easy way out, other than looking for "," and "-|+" to determine which pattern to use.

0
Thierry On

There is a javax.mail class that perform the parsing of RFC-2822 dates :

javax.mail.internet.MailDateFormat

including the optional and obsolete formats.

Just do :

new javax.mail.internet.MailDateFormat().parse("Sat, 13 Mar 2010 11:29:00 -0800")
new javax.mail.internet.MailDateFormat().parse("13 Mar 2010 11:29:00 -0800")
new javax.mail.internet.MailDateFormat().parse("13 Mar 2010 11:29 -0800")

It will correctly parse these valid RFC-2822 dates

As for other old DateFormatters, the MailDateFormat class is not thread safe.