iOS NSDateFormatter behaving differently on device - ios

I have the following code to create NSDate objects from NSString objects.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"hh:mm aa M/dd/yyyy"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
NSString *day = #"3/26/2015";
NSString *time = #"10:24 PM";
NSString *dateString = [NSString stringWithFormat:#"%# %#", time, day];
NSDate *date = [dateFormatter dateFromString:dateString];
This piece of code works perfectly on the simulator, yielding the exact corresponding time in my time zone. However when I run this on a device with iOS 8, date is set to nil.
The format I'm using is supposed to work according to this page that is referenced by this Apple Developer page.
Any help or information on this would be much appreciated. Thanks in advance.
Edit: I'm trying to create NSDate objects from formatted NSString's, not get the date from the system in a predefined fromat. The possible duplicate of this question is probably closely related but I couldn't get the solution to work in my situation.
Edit 2: I've just noticed this problem only occurs when 24-Hour Time is enabled in Settings. However, there is no way for me to know which format the device owner is using, so I'm still in need of a solution.

When working with such strict date formats, you need to set the locale to avoid having issues with the device current locale when formatting dates. Otherwise, the NSDateFormatter will use the device's locale, which explains the fact that it happens only when you enable 24-Hour Time in Settings.
See Apple's documentation:
In all cases, you should consider that formatters default to using the user’s locale (currentLocale) superimposed with the user’s preference settings. If you want to use the user’s locale but without their individual settings, you can get the locale id from the current user locale (localeIdentifier) and make a new "standard” locale with that, then set the standard locale as the formatter's locale.
For example, in your case, you could use the en_US_POSIX:
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
dateFormatter.locale = enUSPOSIXLocale;

Related

iOS 11 [NSTimeZone localTimeZone] ignoring [NSTimeZone defaultTimeZone];

When I launch my app, I set my default timezone to GMT
[NSTimeZone setDefaultTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
Then, on subsequent calls to [NSTimeZone], I use -localTimeZone. Until iOS 10, everything worked properly and I got GMT-0 as the returned timezone. Now, on iOS 11, I get my localtime, which is GMT-3.
Also, if I call -defaultTimeZone instead, I also get GMT-0, which is the right answer. Someone nows why -localTimeZone changed its behavior?
It's a bug in iOS11. I filed a radar it's marked by Apple as "DUPLICATE OF 33629367"(still an open issue as of iOS11.1 beta). In most cases it's best to stop using localTimeZone... it is a bit of a threading nightmare.
How things are supposed to work:
[NSTimeZone systemTimeZone] returns the system timezone always. If the system timezone changes then you have to requery this method(the NSTimeZone returned doesn't autoupdate)
[NSTimeZone defaultTimeZone] returns systemTimeZone unless a defaultTimeZone has been set. If the default or system timezones change then you have to requery this method(the NSTimeZone returned doesn't autoupdate)
[NSTimeZone localTimeZone] returns a timezone equal to what defaultTimeZone returns. The NSTimeZone returned DOES autoupdate if systemTimeZone or defaultTimeZone change. So it could update on you in the middle of a function.
In iOS11, [NSTimeZone localTimeZone] seems to be equivalent to [NSTimeZone systemTimeZone]

Strange Xcode behaviour

I am about to raise this as a bug with apple support but it takes a long time to get any response from them so ... I wanted to ask here.
Debugging an app where i use some dateTime conversions between timezones.
I get the following strange behavior and I wonder if anyone else has seen this and knows how to fix it.
Xcode 8.3.2
You can see that the GMTDate is displaying 2 completely different date/time values ( they aren't even related values) and it is difficult to know which one is correct.
I have restarted Xcode /computer, etc, but still the same!
Screenshot attached:
- (NSString*) convertToDeviceTime:(NSString*) GMTDate {
//create the formatter for parsing
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
[df setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
//parsing the string and converting it to NSDate
NSDate *myGMTDate = [df dateFromString: GMTDate];
//create the formatter for the output
NSDateFormatter *out_df = [[NSDateFormatter alloc] init];
[df setTimeZone:[NSTimeZone systemTimeZone]];
[out_df setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
//output the date
NSString *myDeviceDate =[out_df stringFromDate:myGMTDate];
NSLog(#"the date is %#",myDeviceDate);
return myDeviceDate;
}
new screenshot below - this has to be something wrong with Xcode,
the real value of 'token' shows in the quick look, but the debugger window shows it as a date! Weird. I have restarted the Mac, still the same.
Update: It is happening with all NSString variables. As soon as I write a value to them, the debugger window shows them with the same date value. If I print them to the console or NSLog, then the values are shown correctly.
Found the culprit.
In the debugger the "Edit Summary Format" popup I had somehow inadvertently pasted this date value, and it was showing this for all NSString values.
FYI:It is NOT project specific, so when I loaded another project, it kept that "Edit Summary Format" string and applied it to all NSStrings.
Kudos to an older SO post here: Strange values displayed in Xcode debugger
Screenshots attached!

NSDateFormatter returns nil since upgrade to ios8

I have the following NSDateFormatter:-
self.dateFormatter = [NSDateFormatter new];
[self.dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss'Z'"];
[self.dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
My string comes from a webmethod outputting a json String and is as follows:-
"2014-04-09T23:00:00Z"
My code to get the date is:-
estimate.date = [self.dateFormatter dateFromString:jsonDate];
This was working fine for ios7 and the early builds of ios8. However I was not working on this project for some months and when I came to fix some reworks I installed the latest xcode (6.4) and the latest ios (8.4.1) and now the above code returns nil.
I have googled the hell out of this and everything says this should work.
The only way around this is to set the locale to en_GB which forces the NSDateFormatter to use 24hours. It seems it ignores HH or hh and uses whatever the current locale is set to unless you override it!
[self.dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_GB"]];

iOS Date format issue within App receipt

I am parsing the JSON returned from App Store when verifying a receipt.
One of the public fields is original_purchase_date. However, the date that is returned here is in the format of "2014-05-30 14:05:51 Etc/GMT". The issue being that when I try to compare this, the suffix (Etc/GMT) appears to be causing issues. I am trying to understand how to manage this, as this suffix could be any timezone (say America/Los_Angeles or whatever).
Is there a way of converting this into a useable format?
I know in the receipt there is also a field original_purchase_date_ms which is seconds since 1970 I suspect, however, this is a private field (not called out in any docs), so I don't want to rely on its use, only to find the app rejected, or Apple later remove the field!
Thanks in advance.
Sample Code:
NSString *oldDateStr = [NSString stringWithFormat: #"2014-05-30 14:05:51 Etc/GMT"];
NSString *newDateStr = [oldDateStr stringByReplacingOccurrencesOfString:#"Etc/GMT" withString:#""];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *date1 = [dateFormat dateFromString:newDateStr];

Iphone NSDateFormatter - image files could not be loaded

In my sqlite db I have a NSDate field and I create a image file with a unique name using this code and based on that date I load the image.
NSDateFormatter *digitsOnlyDateFormatter = [[NSDateFormatter alloc] init];
[digitsOnlyDateFormatter setDateFormat:#"yyyyMMddHHmmss"];
NSString *imageDateString = [digitsOnlyDateFormatter stringFromDate:[self imageDate]];
If I change the time zone from iphone settings and I add a new record in db, other images saved with another time zone could not be loaded.
I think there is a problem with conversion.
Can someone help me?
Part of NSDateFormatters format can be overridden by user settings: specifically the choice of AM/PM versus 24-hour time.
You can solve this by setting the formatter's locale. (Note: this is something you should only do in situations like this to create strings that need to be consistent across locales and won't be displayed to the user).
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[digitsOnlyFormatter setLocale:enUSPOSIXLocale];
P.S. if you want the string to be made relative to the same timezone as well, you should also set the formatter's timezone:
[digitsOnlyFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];

Resources