Parsing rfc3339 dates with NSDateFormatter in iOS 4.x and MacOS X 10.6: impossible?

Parsing a rfc3339 date with NSDateFormatter appears to be impossible, in the general case. Am I wrong? [Edit 2 years later: there is now a way! See below and footnote.]

A not-especially-malleable web service is feeding me dates like:

2009-12-31T00:00:00-06:00

Rfc3339 compliant, default output of the jaxb library they're using. Note the colon, which rfc3339 requires when the offset isn't a literal "z":

time-numoffset  = ("+" / "-") time-hour ":" time-minute
time-offset     = "Z" / time-numoffset

I want to parse these into NSDates.

NSDateFormatter wants patterns in the syntax specified by Unicode, which offers date field symbols for timezones like "PDT", "-0800", "GMT-08:00" but not "-08:00".

Googling, and other similar SO questions, produces only date formats like

[myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"];
/* or: */ [myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];

The latter of which requires a literal "Z", and the former insists either the absence of a colon or presence of a "GMT". However, they appeared to work before ios 4.x (possibly by discarding the tz offset completely; my data aren't clear.)

My options at this point are a sorry lot:

  • discover some undocumented format specifier, or some strange mode to put NSDateFormatter into, that will accept the stray colon: longshot, likely nonexistent. [footnote]
  • persuade my service publisher to turn all dates into zulu time and specify 'Z': politically challenging.
  • write my own NSFormatter subclass or research good old strptime_l: work. :)
  • string-manipulate my input and strip the last colon: brittle and ugly, but the likely path of least resistance.

Have I understood the situation accurately, that current NSDateFormatter follows unicode strictly without extensions; and the unicode formats are insufficient to fully describe an rfc3339 date?

[FOOTNOTE] I come back to this three years later to tack on a small addendum: Unicode and Apple have added this feature to the format strings, as of iOS6/OSX10.8. Compare The latest revision as of this writing with its immediate predecessor, and note the addition of 5 "Z"s, which yields a zone format like "-08:00". So if you can get away with ditching support for 5.x/10.7, there's a new right way to do it. I'll leave the previous answer stand, as it's still the best approach when backward compatibility is required.

Answers


Date string parsing in Cocoa can be a pain, especially if you have to deal with dates generated by .NET based web services.

I'd suggest looking at the NSDate+InternetDateTime category that Michael Waterfall has on NSDate as part of his MWFeedParser project on github. It's worked well for me parsing exactly the format of date you describe.

https://github.com/mwaterfall/MWFeedParser/


– getObjectValue:forString:range:error: can actually parse RFC3339 dates correctly. I have no idea why - dateWithString: cannot:

// RFC3339 date formatting
NSString *dateString = @"2012-04-11T18:34:19+00:00";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";

NSDate *date;
NSError *error;
[formatter getObjectValue:&date forString:dateString range:nil error:&error];

Need Your Help

Git new file appears in all branches

git merge branch commit rebase

I thought a file created on one branch will not appear in any other branches until I merge or rebase the branch?

Does Handler execute Runnable's simultaneously

android

A non-UI thread in my Android application contains a Handler object, and I add implementations of Runnable to this Handler using the post() method.

Transmitting data with CoreBluetooth

ios bluetooth core-bluetooth bluetooth-lowenergy

I'm developing an iOS app with an accompanying Bluetooth LE peripheral. The one step I don't seem to be able to solve is how to actually transmit the data from my app to the peripheral or vice ver...