7

I would like to parse ISO8601 dates in Cocoa, both for iOS 4+ and OSX 10.6+

There are a few questions about this on StackOverflow already, but in my opinion none of them contain good answers. Here's what I think constitutes a good answer:

  1. The answer should point to code with support for ISO8601. This code should compile cleanly under XCode 4 for both iOS 4+ and OSX 10.6+.

  2. The code should support all possible ISO8601 date formats.

    Please note that there are many, many possibilities here. Simply answering with one or two format strings for NSDateFormatter is not going to cut it.

  3. The answer should not be this library. That's because it is riddled with dangerous 32-bit assumptions, it's far more complicated than necessary, and it doesn't compile clean with XCode4/Clang. Bottom line: I don't trust it at all!

Thanks, fellow Cocoa-ites. I'm excited to find out if there's a real answer here!

Community
  • 1
  • 1
Dave Peck
  • 1,342
  • 1
  • 17
  • 24

1 Answers1

6

The best way is this library. ☺

I should add a link on that page to the Bitbucket repo, which contains newer source code (including 32-bit and Clang fixes!) and has an issue tracker. If you find any other bugs in it, please file them.

I'd also like to know what you mean by “more complicated than necessary”. Normal usage is very simple:

ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease]; //Or, if you prefer, create it once in -init and own it until -dealloc 
NSDate *parsedDate = [formatter dateFromString:inString];
NSString *unparsedString = [formatter stringFromDate:inDate];

You can switch out dateFromString: or stringFromDate: for one of the longer methods if you need more information (e.g., to preserve the time zone).

If you mean something else, I want to hear it so I can improve the library.

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
  • 1
    Ha! Hi, Peter. Great, I'll take a look at the code on Bitbucket and see how it goes. By "more complicated than necessary," I have to admit: what I meant was that after visual inspection I decided that your library's code was probably hard to maintain. It doesn't "read" to me like clean, modular, well-factored code. That plus the 32/64 issues convinced me to look elsewhere. That said, ISO8601 is a tricky beast, as are parsers... so I'm happy to be corrected on this point, possibly by telling me to write my own darned ISO8601 parser. ;-) – Dave Peck Jun 01 '11 at 02:09
  • Yeah, it's not pretty. Each of the main work methods is long, and there are *six* gotos. Ideally, I'd probably use a regex or three for the parsing; given that Cocoa doesn't yet have a built-in regex API (only Cocoa Touch does), if I ever decide to rewrite it for fun, I might make a custom state machine of some sort. As it is, though, what I'd consider a higher priority is switching to SenTestingKit for the testing. The current code works, but I'd want testing and re-testing to be easier before I'd consider replacing the implementation. (Incidentally: `make test` to run the current tests.) – Peter Hosey Jun 01 '11 at 05:18
  • I'm now using the version of this library found on Bitbucket. It compiles cleanly and, from my limited tests, appears to work. @Peter you should _definitely_ update your website to point to bitbucket -- this will help people realize that your library is still maintained. (As it is, the bitbucket repo is essentially unfindable.) Unless someone chimes in with a different answer to my question in the next couple days, I'll mark @Peter's answer as the accepted one! – Dave Peck Jun 03 '11 at 19:59
  • @Dave Peck: I have updated the page to include the link to Bitbucket. – Peter Hosey Jun 03 '11 at 22:10
  • Awesome! I've been using your library in the latest test build of my app [Cloak](https://www.getcloak.com/) and I'm happy about the behavior. I'm marking this answer as accepted. Thanks again! – Dave Peck Jun 09 '11 at 21:49
  • 1
    This library seems somewhat flawed :-( Correct me if I'm wrong, but I see absolutely no tests for time or timezone parsing and these seem to be the areas that are broken on iOS when I use this code. It doesn't generate valid ISO8601 times and nor will it parse them in its current form. I don't have a working patch yet but if I get one, I'll add another comment. I've raised the initial bug on the issue tracker. – Roger Sep 09 '11 at 18:36
  • As an update, one problem is the ISO_TIMEZONE_OFFSET_FORMAT string. The "%+02d%02d" does not zero pad the first digit as might be expected. You can test this with a simple NSLog("@%+02d%02d",1,0) which gives +100 and not +0100 as required. – Roger Sep 09 '11 at 18:59
  • I think the correct format string needs to be "%+.02d%02d" to specify precision and zero padding rather than zero padding and field width. – Roger Sep 09 '11 at 19:14
  • @Roger: Please take discussion of this bug, including potential causes, to the ticket. – Peter Hosey Sep 09 '11 at 22:15
  • Ticket link for anyone who wants to follow along or provide more information/a patch: https://bitbucket.org/boredzo/iso-8601-parser-unparser/issue/3/conversion-fails-using-am-pm – Peter Hosey Sep 10 '11 at 15:08
  • @Roger: I can't reproduce your problem. I need more information from you: https://bitbucket.org/boredzo/iso-8601-parser-unparser/issue/3/conversion-fails-using-am-pm#comment-670661 – Peter Hosey Sep 26 '11 at 06:25
  • Seems to be working correctly. But I cannot find any documentation on how I change the output string format. :( – Redfox Jan 18 '12 at 14:05
  • @Redfox: Use the `format`, `includeTime`, and `timeSeparator` properties. https://bitbucket.org/boredzo/iso-8601-parser-unparser/src/900c739f57ea/ISO8601DateFormatter.h – Peter Hosey Jan 18 '12 at 22:43