Parsing a RFC 822 date with NSDateFormatter

Anurag picture Anurag · Dec 5, 2009 · Viewed 8.5k times · Source

I'm using a NSDateFormatter to parse a RFC 822 date on the iPhone. However, there is no way to specify optional elements in the date format. There are a couple of optional parts in the RFC 822 specification which is breaking the date parser. If nothing works out, I'd probably have to write a custom parser to obey the specs.

For example, the day name is optional in the spec. So both these dates are valid:

Tue, 01 Dec 2009 08:48:25 +0000 is parsed with the format EEE, dd MMM yyyy HH:mm:ss z 01 Dec 2009 08:48:25 +0000 is parsed with the format dd MMM yyyy HH:mm:ss z

This is what I am currently using:

+ (NSDateFormatter *)rfc822Formatter {
    static NSDateFormatter *formatter = nil;
    if (formatter == nil) {
        formatter = [[NSDateFormatter alloc] init];
        NSLocale *enUS = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
        [formatter setLocale:enUS];
        [enUS release];
        [formatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss z"];
    }
    return formatter;
}

+ (NSDate *)dateFromRFC822:(NSString *)date {
    NSDateFormatter *formatter = [NSDate rfc822Formatter];
    return [formatter dateFromString:date];
}

And parsing the date as follows:

self.entry.published = [NSDate dateFromRFC822:self.currentString];

One way is to try both formats, and take whatever returns non null value. However, there are two optional parts in the spec (day name and seconds) and there would be 4 possible combinations. Still not too bad, but it's a bit hacky.

Answer

mmcdole picture mmcdole · Oct 1, 2013

I've used the following method to parse RFC822 dates. I believe it originally was from MWFeedParser:

+ (NSDate *)dateFromRFC822String:(NSString *)dateString {

    // Create date formatter
    static NSDateFormatter *dateFormatter = nil;
    if (!dateFormatter) {
        NSLocale *en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
        dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setLocale:en_US_POSIX];
        [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
        [en_US_POSIX release];
    }

    // Process
    NSDate *date = nil;
    NSString *RFC822String = [[NSString stringWithString:dateString] uppercaseString];
    if ([RFC822String rangeOfString:@","].location != NSNotFound) {
        if (!date) { // Sun, 19 May 2002 15:21:36 GMT
            [dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss zzz"]; 
            date = [dateFormatter dateFromString:RFC822String];
        }
        if (!date) { // Sun, 19 May 2002 15:21 GMT
            [dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm zzz"]; 
            date = [dateFormatter dateFromString:RFC822String];
        }
        if (!date) { // Sun, 19 May 2002 15:21:36
            [dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss"]; 
            date = [dateFormatter dateFromString:RFC822String];
        }
        if (!date) { // Sun, 19 May 2002 15:21
            [dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm"]; 
            date = [dateFormatter dateFromString:RFC822String];
        }
    } else {
        if (!date) { // 19 May 2002 15:21:36 GMT
            [dateFormatter setDateFormat:@"d MMM yyyy HH:mm:ss zzz"]; 
            date = [dateFormatter dateFromString:RFC822String];
        }
        if (!date) { // 19 May 2002 15:21 GMT
            [dateFormatter setDateFormat:@"d MMM yyyy HH:mm zzz"]; 
            date = [dateFormatter dateFromString:RFC822String];
        }
        if (!date) { // 19 May 2002 15:21:36
            [dateFormatter setDateFormat:@"d MMM yyyy HH:mm:ss"]; 
            date = [dateFormatter dateFromString:RFC822String];
        }
        if (!date) { // 19 May 2002 15:21
            [dateFormatter setDateFormat:@"d MMM yyyy HH:mm"]; 
            date = [dateFormatter dateFromString:RFC822String];
        }
    }
    if (!date) NSLog(@"Could not parse RFC822 date: \"%@\" Possibly invalid format.", dateString);
    return date;

}