Inconsistent behaviour with NSDateFormatter on two different devices - iphone

I'm having a bit of a problem with NSDateFormatter failing on one user's device (returning nil when parsing a string) and working perfectly when I run it locally (either in the simulator or on my device).
I'm trying to rule out what could be causing a difference in this behaviour. My first thought was the locale but I've tried setting it explicitly to ensure the same locale is always used but it makes no difference.
Here is the code:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZ"];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_GB"];
[dateFormatter setLocale:locale];
[locale release];
NSDate *theDate = [dateFormatter dateFromString:dateString];
NSLog(#"PARSING DATE %# AS %#", dateString, theDate);
On the failing device, I get:
PARSING DATE 2010-11-28T20:30:49-0000 AS (null)
But locally I get:
PARSING DATE 2010-11-28T20:30:49-0000 AS 2010-11-28 20:30:49 +0000
This is driving me crazy, am I missing something else?
I am running 4.2 locally (simulator) and on my device (an iPhone 4). The failing device is a 3GS running 4.2.1.
Any ideas would be much appreciated!

I'm pleased to say that I eventually got to the bottom of this issue and I must pass on my thanks to #bendodson on Twitter for helping me out with this. aBitObvious also hit on the issue in his comment above; I'd have up-voted him if I could.
There was one difference between the user's device and mine, and that was that his device was set to use the 12 hour clock and mine was not. This single thing meant that the NSDateFormatter was unable to parse the time in the above examples and returned nil.
By far the biggest issue for me with this problem was being unable to reproduce the problem locally!
So, to be clear, to solve this issue; that is, if you are parsing date/time strings that are in a known, fixed format (often coming from some API as this was in my case), you should set the correct locale for the date formatter, which will often be en_US_POSIX.
...
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[dateFormatter setLocale:locale];
[locale release];
For more information on this, read Apple QA1480.

Related

xcode 4.2 location simulator and Time Zone

I noticed a nifty setting in the xcode simulator while running that I can change the current location and hence simulate location based tests
However, when I try to get the date using NSDateFormatter, the local date is still in PST. I am in the Pacific Time Zone
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle]; // Jan 1, 2010
[dateFormatter setTimeStyle:NSDateFormatterShortStyle]; // 1:43 PM
NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
[dateFormatter setLocale:usLocale];
[usLocale release];
NSDate *testDate = [NSDate date];
NSLog(#"Local date: %#", [dateFormatter stringFromDate:testDate]);
According to the docs, stringFromDate should use the receivers current setting, which should use the timeZone of the Tokyo, Japan.
Is this expected?
Chech the - timezone-attribute of the NSDateFormatter - I think this is controlled by the device itself (or your computer in this case), not the location. There is a setting in the settings-app however that lets you set the time by location, I'm not sure if that would change anything, but try activating that.
And a general tips: always test it on a device as well - I think the "Simulate Location"-setting works on the phone as well.
Edit: Just saw an answer that could be relevant, try calling [NSTimeZone resetTimeZone]; after setting a new location. That should trigger a reset and hopefully display the correct timezone. Ref: https://stackoverflow.com/a/5987409/267892

NSDateFormatter ignores the AppleLanguages in NSUserDefaults

My App is translated into several languages, but for now I want to force the language to Dutch. I did force the language to Dutch by setting the AppleLanguages key in the standardUserDefaults to Dutch. This is working for localized strings and xib files.
But the NSDateFormatter seems to ignore this value completely. It's just using the iPhones en_US locale to format the date, even if I set the locale myself on the NSDateFormatter object:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSLocale *dutch = [[NSLocale alloc] initWithLocaleIdentifier:#"nl_NL"];
[dateFormatter setLocale:dutch];
[dutch release];
[dateFormatter setDateStyle:NSDateFormatterLongStyle];
dateLabel.text = [dateFormatter stringFromDate:[BabyInfo getDate]];
[dateFormatter release];
Does anyone have a clue how to solve this?
Update: So it seems the all the date stuff (like NSDateFormatter and NSDatePicker) are not using the language locale to determine what type of date to show, but are looking at the location locale. Still, I don't know how to tell the formatter and picker that I want them to show their dates in Dutch. So any help is still welcome, but at least I now understand what the problem is.
Maybe this answer comes too late but check this out:
http://www.alexcurylo.com/blog/2011/02/16/tip-nsdateformatter-localization/
This will force the Formatter/Picker to use the locale with the preferred language without having to change your iPhone/iPad settings.
To use the selected language for your date formatter use:
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[NSLocale preferredLanguages] objectAtIndex:0]]];

NSDate and different timezones?

Alright. Our application sends an NSString made out of the current user's username and todays date formatted in yyyyMMddHH. Our server, that is located in sweden, makes the exact same String and compares the two when it gets the call.
Now. We have realized, that if one of our users goes abroad, the timezone will change, resulting in complications.
if the iPhone user were to be in lets say, Seoul, South-korea. His NSString that is sent would be something like:
2011061718
Meanwhile, when our server gets the call, it will recreate its own datestring in this format because it's located in sweden.
2011061711
And therefore deny the user access to the functions on the server side.
To summarize:
How do i programmatically set a default static timezone in my application?
Atm we do this:
NSDate *aDate = [aDateFormatter stringFromDate:[NSDate date]];
And somehow we need the timezone and compare the difference between the user's actual timezone and change it to a swedish-timezone.
Any ideas?
EDIT: Ok. This application is only meant to be released in sweden. And we are using a combination of the user's username and the current date in the format of yyyyMMddHH to make a secure key, the key is meant to update itself whenever a new hour starts. The server, which is located in sweden in the timezone of GMT+1 makes a verification that the user is on an actual device using the application and not someone who has made a client of his own making soap-calls to our service.
Therefore, if one of our users goes outside the timezone, it will reject the user since the strings wont match.
This is why we want to set the default timezone for that function GMT+1 at all times. And this is what we're really looking for.
Thanks. Again.
If you need to make the client format the date, this is how to do it:
NSDate *now = [NSDate date];
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:#"Europe/Stockholm"]; // Sets the right time.
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]; // Forces the date formatter to accept any format string.
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setCalendar:gregorianCalendar];
[formatter setTimeZone:timeZone];
[formatter setDateFormat:#"yyyyMMddHH"];
[formatter setLocale:locale];
NSString *dateString = [formatter stringFromDate:now];
NSLog(#"Date: %#", dateString);
[locale release];
[gregorianCalendar release];
[formatter release];
The date formatter will do all the work for you, you just need to configure it.
By setting the gregorian calendar, you're using the same calendar as in Sweden.
By setting the timezone, you'll get the time as it would be in Sweden.
By setting the locale to "en_US_POSIX" you make the formatter use the exact format you specify, and not append any AM/PM stuff.
Don't mess about with that. Send complete date time as a string and let the server figure out the times.
NSString *dtString = [[NSDate date] description];
This will create a string with the format
YYYY-MM-DD HH:MM:SS ±HHMM
Use -[NSDateFormatter setTimeZone:]. NSDate has nothing to do with it as it does not care about time zones.
Btw, your code will also fail if the user uses a different calendar.
Also a heads up, if you turn the AM/PM function on the dateformatter will pring out 'AM/PM' even if you dont place it in the format string.
To fix this also add an NSLocale to the DateFormatter.

NSString to NSDate conversion problem

I am having a NSString object which I am converting to NSDate with help of NSDateFormatter. Now code works fine here with all the OS but it is creating different Output at client's add (USA region).
Here is the code that I am using.
NSDateFormatter *formate = [[[NSDateFormatter alloc] init] autorelease];
[formate setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSString *strConcat = #"2010-09-24 17:30:00";
NSDate *date = [formate dateFromString:strConcat];
NSLog(#"Output :%#",date);
Output at my end -------2010-09-24 17:30:00 - 0700
Output at Client end ----2010-09-25 00:30:00 GMT
Can anyone please suggest where's the problem?
Thanks
Pratik Goswami
The only output difference I notice is the time is different. If you do not explicitly set the timeZone property of the formatter it will use the system's local timezone. If you expect the times to the be the exact same from you and your client:
[formate setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
That would insure the output is always GMT.
You need to manually set the locale for the NSDateFormatter, so that all your users see the same formatted string. Otherwise, the formatter will use whatever locale is set for the device.
Actually, it's working correctly. The two dates are equivalent, just that one is in the US/Mountain time zone and the other is in the Greenwich time zone. (5:30pm + 7 hours = 12:30 am)
What's the problem here?
In iOS2.x and 3.x the description/datefromstring function returns:
2010-09-24 17:30:00 - 0700
in iOS 4.x it returns this:
2010-09-25 00:30:00 GMT
You could submit a bug to apple.

IOS4 NSDateformatter return nil, before in 3.1.3 OK

I know there are a lot of answers about that problem, but I need someone explain me easy, why on SDK 3.1.3 the code bellow returns the correct result, and in the same code in IOS4 return nil.
Thanks a lot for any suggestion.
Marcello
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *testOut = [dateFormatter dateFromString:[itemAtIndex objectForKey:#"data"]];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateStyle = NSDateFormatterShortStyle;
NSString *pippo = [NSString stringWithFormat:#"%# >",[df stringFromDate:testOut]];
5/6/2010
Hi,
I tried to solve with this code by following your information:
NSString *myDate = [NSDateFormatter localizedStringFromDate:[itemAtIndex objectForKey:#"data"] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterShortStyle NS_AVAILABLE(10_6, 4_0)];
but I get only invalid CFStringRef...
It is just a little bit frustrating
Have you any suggestion..
Thanks for your time..
Marcello
Not quite sure what I was thinking..my old answer doesn't make any sense.
I just tested the code you have pasted in iOS 4.0 and it works fine.
What part of this code is returning nil?
The problem was in the [dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"], the right command is "yyyy-MM-dd HH:mm:ss ZZZZ".
Intact, if I understood it correct, the time in SQLITE format is with + 01:00 at the end of the string, to indicate the local time from the Greenwich time. It drive me crazy....
It's a strong thing because since the 3.1.3 sdk the code worked fine.
This answer is for the people like me....
p.s. For Joshua, I didn't receive your reply trough the notify e-mail, but I like to tell you how I resolved my question and give you thanks for spent your time for my question.
Ciao
Marcello