32

I have a timestamp coming from server that looks like this:

2013-04-18T08:49:58.157+0000

I've tried removing the colons, I've tried all of these:

Converting an ISO 8601 timestamp into an NSDate: How does one deal with the UTC time offset?

Why NSDateFormatter can not parse date from ISO 8601 format

Here is where I am at:

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


    NSDateFormatter *dateFormatter;
    dateFormatter = [[NSDateFormatter alloc] init];

    //@"yyyy-MM-dd'T'HH:mm:ss'Z'" - doesn't work
    //@"yyyy-MM-dd'T'HH:mm:ssZZZ" - doesn't work
    //@"yyyy-MM-dd'T'HH:mm:sss" - doesn't work 

    [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
    [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];

    // NSDateFormatter does not like ISO 8601 so strip the milliseconds and timezone
    dateString = [dateString substringWithRange:NSMakeRange(0, [dateString length]-5)];

    return [dateFormatter dateFromString:dateString];
}

One of my biggest questions is, is the date format I have above really ISO 8601? All the examples I have seen from people the formats of each are slightly different. Some have ...157-0000, others don't have anything at the end.

Community
  • 1
  • 1
random
  • 8,568
  • 12
  • 50
  • 85

4 Answers4

63

This works for me:

NSString *dateString = @"2013-04-18T08:49:58.157+0000";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
// Always use this locale when parsing fixed format date strings
NSLocale *posix = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
[formatter setLocale:posix];
NSDate *date = [formatter dateFromString:dateString];
NSLog(@"date = %@", date);
rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • 1
    Yes, it may work without the locale but under certain cases (various user settings) it will not. To ensure your code will always work, set the locale to the special posix locale. – rmaddy Jul 09 '13 at 23:13
  • It should be said that if you actually want it in timestamp format you want to change the NSLog statement at the end to the following: NSLog(@"date = %f", [date timeIntervalSince1970]); – Supertecnoboff Mar 13 '14 at 18:34
  • Thanks @rmaddy, I've thrown away my old POSIX strptime() code in disgust now! – Echelon Jan 30 '15 at 18:38
  • 3
    Also note that allocating NSDateFormatters will affect performance if you're calling this a lot (e.g. churning through chart data points), so you'll want to only do the allocation once. – Echelon Jan 30 '15 at 18:41
  • This unfortunately doesn't work. This solution will not parse a date such as "2013-01-28", which (according to Wikipedia), is a valid ISO 8601 date. I know there are more or less complex solutions on the web, but is there a way to set a plain NSDateFormatter in such a way that it will parse any legal ISO 8601 date? – Jean-Denis Muys Oct 27 '15 at 15:19
  • Also, I tried to set the `NSDateFormatter`'s calendar to the `NSCalendar` with identifier `NSCalendarIdentifierISO8601`. This doesn't seem to make a difference. Does anybody know what is this `NSCalendar` good for? I could not find any useful information about it – Jean-Denis Muys Oct 27 '15 at 15:20
  • 1
    @Jean-DenisMuys This question really isn't about every possible ISO 8601 date format but just one of them. You would need to try each individual format to see which returns a non-nil `NSDate`. You should open your own question if you need help with that. – rmaddy Oct 27 '15 at 15:21
19

There is New API from Apple! NSISO8601DateFormatter

NSString *dateSTR = @"2005-06-27T21:00:00Z";
NSISO8601DateFormatter *formatter = [[NSISO8601DateFormatter alloc] init];
NSDate *date = [formatter dateFromString:dateSTR];
NSLog(@"%@", date);
test
  • 311
  • 2
  • 4
2

I also have the native API, which is way cleaner... This is the implementation I got in my DateTimeManager class:

+ (NSDate *)getDateFromISO8601:(NSString *)strDate{

    NSISO8601DateFormatter *formatter = [[NSISO8601DateFormatter alloc] init];
    NSDate *date = [formatter dateFromString: strDate];
    return date;
}

Just copy and paste the method, it would do the trick. Enjoy it!

Helen Wood
  • 1,872
  • 2
  • 26
  • 41
0

The perfect and best solution that worked for me is:

let isoFormatter = ISO8601DateFormatter();
isoFormatter.formatOptions = [ISO8601DateFormatter.Options.withColonSeparatorInTime,
                                      ISO8601DateFormatter.Options.withFractionalSeconds,
                                      ISO8601DateFormatter.Options.withFullDate,
                                      ISO8601DateFormatter.Options.withFullTime,
                                      ISO8601DateFormatter.Options.withTimeZone]
let date = isoFormatter.date(from: dateStr);

For further more detail, you can refer to apple's official documentation: https://developer.apple.com/documentation/foundation/nsiso8601dateformatter

Mehul Thakkar
  • 12,440
  • 10
  • 52
  • 81