26

I had the following code working on on OS 3.x

NSString *stringDate = @"2010-06-21T20:06:36+00:00";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZ"];
NSDate *theDate = [dateFormatter dateFromString:stringDate];
NSLog(@"%@",[dateFormatter stringFromDate:theDate]);

but now in the newest xcode 3.2.3 under the iOS4 simulator, the varialble theDate is nil.

I have looked through the class reference and do not see anything deprecated or implemented differently for iOS4 with these specific methods. What did i leave out?

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
AtomRiot
  • 1,869
  • 3
  • 18
  • 24
  • It seems if i strip the "+00:00" from the stringDate and then take away the "Z" from the format, it will work properly but that's not really an option as the dynamic data i get has the timezone attached to it and i don't really want to have to rip that part off for each date i get. And i cannot find any documentation saying that timezone is not supported any longer in this way. – AtomRiot Jun 22 '10 at 16:57
  • 4
    I think i figured it out. The format that I am being given is halfway between RFC 822 and GMT. if i change the "+00:00" to "+0000" then I can use the "Z" on my format. and if i change it to "GMT+00:00" then I can use ZZZZ to get the data properly. It seems that something has been stripped out to handle this hybrid as it was working for me before with OS 3.x. – AtomRiot Jun 22 '10 at 17:32

13 Answers13

41

I found out it works if you do it this way (see below). The key is using the method: - [NSDateFormatter getObjectValue:forString:range:error:]

instead of

-[NSDateFormatter dateFromString]

The complete code:

+ (NSDate *)parseRFC3339Date:(NSString *)dateString 
{
    NSDateFormatter *rfc3339TimestampFormatterWithTimeZone = [[NSDateFormatter alloc] init];
    [rfc3339TimestampFormatterWithTimeZone setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
    [rfc3339TimestampFormatterWithTimeZone setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZ"];

    NSDate *theDate = nil;
    NSError *error = nil; 
    if (![rfc3339TimestampFormatterWithTimeZone getObjectValue:&theDate forString:dateString range:nil error:&error]) {
        NSLog(@"Date '%@' could not be parsed: %@", dateString, error);
    }

    [rfc3339TimestampFormatterWithTimeZone release];
    return theDate;
}
Werner Altewischer
  • 10,080
  • 4
  • 53
  • 60
  • Thanks. dateFromString: and getObjectValue:forSting:range:error: behave differently indeed. The latter does indeed work correctly, while the former chokes on the same string (including the colon). – Joris Kluivers Nov 15 '10 at 10:46
  • 1
    Just to add, I was using this code to parse date strings from a JSON web service. It worked perfectly, but having to initialise an NSDateFormatter for each record made the process extremely slow (18 seconds, to parse 5,000 JSON records, each containing one date string). I moved the NSDateFormatter into my "load JSON records" function, so it only got initialised once, and performance was *much* better (took under 1 second to load the 5,000 JSON records). – Mike Gledhill Oct 13 '14 at 11:55
8

Is your device set to 24 hour or 12 hour clock?

That sounds like an insane question but I've just run into that bug - the dateformatter will adjust your format string according to the current locale which will include the time format settings.

You can force it to ignore them by adding this line :

dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];

Hope that helps.

deanWombourne
  • 38,189
  • 13
  • 98
  • 110
5

This code will remove the extra colon as AtomRiot describes:

Converting it from:

  • NSString *stringDate = @"2010-06-21T20:06:36+00:00";

to:

  • NSString *stringDate = @"2010-06-21T20:06:36+0000";
// Remove colon in timezone as iOS 4+ NSDateFormatter breaks
if (stringDate.length > 20) {
    stringDate = [stringDate stringByReplacingOccurrencesOfString:@":"
                                                       withString:@""
                                                          options:0
                                                            range:NSMakeRange(20, stringDate.length-20)];
}

for more details see: https://devforums.apple.com/thread/45837

Community
  • 1
  • 1
Benjamin Ortuzar
  • 7,801
  • 6
  • 41
  • 46
2

I ran into this issue recently. I ended up using Peter Hosey's ISO8601 parser. It is available here: http://boredzo.org/iso8601unparser/

Elfred
  • 3,851
  • 22
  • 16
  • This saved my life, thanks. I prefer using a specific parser than tinkering with the input date string. – scalbatty Jul 13 '10 at 07:55
2

It seems like the Apple documentation is, well, 'tricky':

The format string uses the format patterns from the Unicode standard (this reference is to version tr35-6 for Mac OS X v10.5; for Mac OS X v10.4 use version tr35-4).

and

iOS: The v10.0 compatibility mode is not available on iOS—only the 10.4 mode is available.

According to version tr35-4:

Use 1 for GMT format, 2 for RFC 822

Z{1} GMT-08:00
Z{2} -0800

But according to the Unicode standard:

Use one to three letters for RFC 822, four letters for GMT format.

Z{1,3} -0800
Z{4} GMT-08:00

So it looks like iOS 4 is using tr35-6 - the Unicode standard, which is why +00:00 now fails against 'Z'.

I tried -08:00 against 'ZZZZ' in my NSDateFormatter and it failed in iOS 4. GMT-08:00, however, did work. It seems the timezone (GMT) is now required, rather than optional as it may have been in iOS 3.

J Bryan Price
  • 1,364
  • 12
  • 17
1

I get the value from dataFormat @"yyyy'-'MM'-'dd'T'HH':'mm':'ss'+'hh:mm";

dandan78
  • 13,328
  • 13
  • 64
  • 78
mshiro
  • 51
  • 2
  • Everything up to the timezone was not giving me any troubles. It was just the timezone part. And I am getting timezone data so i had to alter the input a little before parsing – AtomRiot Jun 27 '10 at 15:48
1

The format that I am being given is halfway between RFC 822 and GMT. if i change the "+00:00" to "+0000" then I can use the "Z" on my format. and if i change it to "GMT+00:00" then I can use ZZZZ to get the data properly. It seems that something has been stripped out to handle this hybrid as it was working for me before with OS 3.x.

AtomRiot
  • 1,869
  • 3
  • 18
  • 24
0

Looks fine to me.

Does it still function correctly on a real device?

If so file a bug report for the simulator, otherwise file a bug report for iOS 4.

Ben S
  • 68,394
  • 30
  • 171
  • 212
  • i cant test on a device yet, mine is messed up right now. I was hoping it was just a simulator problem but the dateformatter just didnt seem to be something that the simulator would have an issue with. – AtomRiot Jun 22 '10 at 16:03
  • ok, just tried this code on a device and i see the same behavior as the simulator. :( – AtomRiot Jun 22 '10 at 16:10
0

I was just debugging this exact same problem. I have the same date string as you that works in 3.x and not 4.0. Same symptoms.

When looking through the NSDateFormatter documentation I see:

Initializing a Date Formatter – init Available in iPhone OS 2.0 through iPhone OS 3.2

This says that the init method has been deprecated for iOS 4.0. I'm not sure what that means.

Jeff Zacharias
  • 381
  • 3
  • 12
  • I also saw that when reading through the class reference but it makes no other mention of what it means. And Xcode does not mark it as depricated. – AtomRiot Jun 27 '10 at 15:49
0

The link Elfred posted did the trick. I stumbled upon the same issue whilst converting my app from 3.1.3 to iOS4. The link holds the ISO8601DateFormatter class which is a far more excellent extension then my own date utility class.

Elfred wrote: I ran into this issue recently. I ended up using Peter Hosey's ISO8601 parser. It is available here: http://boredzo.org/iso8601unparser/

0

It seems the NSDateFormatter has gotten very picky.

-(void)dateFormatterTests {
    NSDateFormatter *formatter;

    formatter = [[NSDateFormatter alloc] init];

#ifdef WORKS
    [formatter setDateFormat:@"yyyy-MM-dd"];
#elif defined(ALSO_WORKS)
    [formatter setDateFormat:@"yyyy MM dd"];
    [formatter setLenient:YES];
#else // DOESN'T WORK
    [formatter setDateFormat:@"yyyy MM dd"];
#endif

    // Works per comments above
    NSLog(@"dFS: %@", [formatter dateFromString:@"2010-01-13"]);  
    // Never works with any of the above formats
    NSLog(@"dFS: %@", [formatter dateFromString:@"2010-01-13 22:00"]); 

    [formatter release]; formatter = nil;
}
John Franklin
  • 4,962
  • 1
  • 23
  • 27
  • This code does not take into account the time zone. I am being given the time zone in a specific format and i cannot change that. – AtomRiot Jul 22 '10 at 02:51
  • I'm sorry. That point of the post was to show there formatter would return nil in cases where you'd think it should produce something, such as when decoding only a date, but also adding a time in the string. I'm glad you got it working. – John Franklin Jul 22 '10 at 17:39
0

I had the same issue in my apps as well Null Value from NSDateFormatter.

I found my problem to be the following:

I was sending my app a date and time like this: 07/16/2010 04:21:00 +00:00 with the formatter like this: [dateFormatter setDateFormat:@"MM/dd/yyyy HH:mm:ss ZZZ"]

It seems like the ZZZ part of the formating NO LONGER accepts the colon : in the time.

Works: 07/16/2010 04:21:00 +0000

Doesn't work: 07/16/2010 04:21:00 +00:00

To support the current apps that are out, all I did was search for the +00:00 part in the string and replace it with +0000.

Hope this might help others.

Community
  • 1
  • 1
RoLYroLLs
  • 3,113
  • 4
  • 38
  • 57
0

I'm using it as simple as:

date_formatter = [[NSDateFormatter alloc] init];
        [date_formatter setDateStyle:NSDateFormatterShortStyle];
        [date_formatter setTimeStyle:NSDateFormatterNoStyle];

and this is working great. I don't understand how can they deprecate the init method, when the NSDateFormatter class is subclassed from NSObject

chunkyguy
  • 3,509
  • 1
  • 29
  • 34