iOS System locale identifier is empty - ios

I've noticed something weird while using date formatters. Below is the code for the date formatter.
let formatter = NSDateFormatter()
formatter.dateFormat = "EEE dd MMM h:mm a"
formatter.locale = NSLocale.systemLocale()
print(formatter.stringFromDate(NSDate()) )
The output is: "Fri 18 M03 1:05 PM". Which is kind of weird. However removing the formatter's locale gives me the output that I want: "Fri 18 Mar 1:05 PM".
I also tried printing out NSLocale.systemLocale(), and the output is an empty string. Is that normal? And what is actually happening to the date formatter when you change the locale?
FYI: I'm testing this on an actual device. And also changing the Region formats in device settings have no affect on the locale identifier.

If you want to use the system setting, should use this one NSLocale.currentLocale()
In Apple's API Document already have a point on this.
Discussion
Use the system locale when you don’t want any localizations. Use the current locale to format text that you display to users.
FYI: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSLocale_Class/index.html#//apple_ref/occ/clm/NSLocale/systemLocale

Related

DateFormatter wrong time output when a different month is selected

I have a separate DatePicker and TimePicker component in my app.
Once the user has selected both the desired Date and Time, I construct a new Date object like this:
let timeStamp = Date(year: selectedDate.year, month: selectedDate.month, day: selectedDate.day, hour: selectedTime.hour, minute: selectedTime.minute)
I then use DateFormatter to output the exact time that the user has selected like this:
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm"
formatter.string(from: timeStamp)
Now I have a very weird bug where sometimes time output will be correct (time will be displayed in UTC+2) and sometimes it'll be incorrect (time will be displayed in UTC+1) and I have absolutely no idea what could be causing this.
Example 1 (correct output):
User selects: May 26, 2020 - 18:38
Date ISO output: "2020-05-26T16:38:00Z"
DateFormatter output: "18:38"
This is the correct output
Example 2 (wrong output):
User selects: March 26, 2020 - 18:38
Date ISO output: "2020-03-26T16:38:00Z"
DateFormatter output: "17:38"
This is not the correct output. Time should be 18:38 like in the above example.
Someone please tell me how is this possible? Literally the only difference is user picked March instead of May (different month) and that for some reason confuses the DateFormatter, so Time output is in a different timezone.
I am using SwiftDate to work with dates in general.
Set correct formatter.locale, you can try Locale(identifier: "en_US_POSIX") or try to use formatter.timeZone property. Maybe TimeZone.current or TimeZone(secondsFromGMT: 0) will fix your problem
That is probably because in May daylight saving is in effect and the difference to UTC changes from +1 to +2 hours
You can use the current TimeZone and add configure your DateFormatter with it
let timezone = TimeZone.current
dateFormatter.timeZone = timezone
That should make sure that you always use the same timezone that is currently used by your device

Incorrect locale from dateFormatter

I have problem with my DateFormatter.
My iOS app communicates with server and uses If-Modified-Since header with date created with following formatter:
modifiedSinceDateFormatter = DateFormatter()
modifiedSinceDateFormatter!.dateFormat = "EEE, dd MMM yyyy HH:mm:ss zzz"
modifiedSinceDateFormatter!.locale = Locale(identifier: "en_US")
modifiedSinceDateFormatter!.timeZone = TimeZone(abbreviation: "GMT")
It works as expected - returning date in following format: Fri, 08 Sep 2017 07:02:20 GMT.
But I was looking through the server logs and found that once request was made with following date format sob., 26 sie 2017 10:17:01 CEST (that's correct Polish locale and timezone - I expect my users to use Polish locale).
So my question is:
How is it possible that this formatter returned date in the wrong locale? Are there some options that user can activate to override this locale (like Accessibility options)? Can it be some jailbroken device?
EDIT: And it happened again: wt., 17 kwi 2018 08:40:02 CEST. Interesting that there was few requests (at same moment from single device) and only one of them failed - with wrong date).
I found the following explanation on how to ensure you get your date properly parsed using English names for months and days
Unless you specifically need month and/or weekday names to appear in the user's language, you should always use the special locale of en_US_POSIX. This will ensure your fixed format is actually fully honored and no user settings override your format. This also ensures month and weekday names appear in English. Without using this special locale, you may get 24-hour format even if you specify 12-hour (or visa-versa). And dates sent to a server almost always need to be in English.
I found the quote on this page

NSDateFormatterStyle.MediumStyle doesn't show in iPhone

I'm using NSDateFormatterStyle.MediumStyle in my application to convert the date. I display the date on label with font size of 12
It functions on the
iPad
simulator it show like "nov 12,1994" but on my
iPhone
device it shows short formatter: "11/12/1994".
Do you know why it function on the iPad but not in the iPhone
From the NSDateFormatterStyle documentation :
The format for these date and time styles is not exact because they
depend on the locale, user preference settings, and the operating
system version. Do not use these constants if you want an exact
format.
That said, I assume your iPad and your iPhone are set to different locales
If you want your dates to be as per the iPad example above across all locales, you can create your own formatter
let date = NSDate()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MMM d, yyyy"
dateFormatter.stringFromDate(date)

iOS app occasionally sends an invalidly-formatted ISO8601 date to REST API

A couple of times a day, our PHP REST API logs an error causing by an invalidly-formatted ISO8601 date, coming from a GET request sent by our iOS app. The interesting thing is that most of the calls are fine (eg. 2015-07-07T00:00:00+10:00), but every so often we get a strange one (eg. 2015-07-07T12:00:00 am+10:00).
The code I believe is causing this is as follows:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];
NSString *iso8601StringStart = [dateFormatter stringFromDate:self.searchStartTime];
Is there any circumstance in which NSDateFormatter could somehow (incorrectly) get am/pm from "yyyy-MM-dd'T'HH:mm:ssZZZZZ", when it's clearly the unintended behaviour? Are there certain kinds of NSDate that cause different behaviour? I'm stumped. The date given is always created via dateFromComponents.
I do not believe that that format string could ever generate the date with the am/pm annotations which you show. If I were you, my first course would be to double check that those dates are really being generated by those lines of code.
However, if you're sure this is happening, the only issue I can see is that it might be incorrect that you are not explicitly setting the locale and the calendar of the date formatter object. The date format syntax is defined by the unicode consortium, and the governing spec does say in section 4.5 that "If locales are not listed, dayPeriods fallback to AM/PM". I don't understand the whole document, but it suggests that being very explicit is the safest path.
If your only requirement is ISO8601, then you could use RFC3339 in UTC time zone, since this is a profile of ISO8601. This creates a correct formatter for that format:
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z"
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
formatter.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601)!
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
My final solution (towards which I was nudged by algal's answer):
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]];
The Unicode spec was helpful (thanks algal), as was this Apple Technical QA, which suggested the en_US_POSIX as a specific solution.
"On iOS, the user can override the default AM/PM versus 24-hour time setting (via Settings > General > Date & Time > 24-Hour Time), which causes NSDateFormatter to rewrite the format string you set, which can cause your time parsing to fail."
Most helpfully, I found this explanation of the behaviour by huyz, although a little old:
When iPhone users change their region format between, say, “United States” and “France”, the users’ “24-Hour Time” setting is automatically switched to the mode that is most prevalent in that region. In France, that would set 24-Hour Time to “ON”, and in the U.S., that would set it to “OFF”. The users can then manually override that setting and that’s where trouble starts.
The problem comes from NSDateFormatter somehow “getting stuck” in the 12 or 24-hour time mode that the user has manually selected. So if a French user manually selects 12-hour mode, and the application requested NSDateFormatter to output time with the 24-hour format “HHmm”, it would actually receive time in a 12-hour format, e.g. “01:00 PM”, as if the application had instead requested “hhmm aa”. The reverse would happen if a US user manually selected 24-hour mode: outputting time with the 12-hour format “hhmm aa” would actually get you time in the 24-hour format instead, e.g. “17:00″.

How to format a date depending on the locale used?

I have a date that I would like to format depending on what country the user is from.
The date: 10th of March 2015.
Let's say the user is from USA, I'd like: 03/10/15
Let's say the user is from France, I'd like 10/03/15
I guess I could check if the locale is like en-US and fr-FR and format it accordingly but is there a way to make it automatic and for all locales?
You can use the defaultTimeZone of NSDateFormatter()
var dateFmt = NSDateFormatter()
dateFmt.timeZone = NSTimeZone.defaultTimeZone()
You can use one of the NSDateFormatter styles:
NSDateFormatterNoStyle
NSDateFormatterShortStyle
NSDateFormatterMediumStyle
NSDateFormatterLongStyle
NSDateFormatterFullStyle
Or if you already have a format string in mind (like "MM-DD-YYYY") you can pass it through [NSDateFormatter dateFormatFromTemplate:options:locale:];

Resources