11

For some reason some devices fail to convert a string to a date.

This is my date converting code:

func dateFromString(string: String) -> Date? {
    let f = DateFormatter.init()
    f.dateFormat = "yyyy-MM-dd HH:mm:ss"
    return f.date(from: string)
}

Now, through my analytics platform I capture when this return nil. I have no clue why so. I assume it has something to do with local and maybe timezone or 12/24h settings but I can't figure out what is the problem.

More Details...

I have tracked the following settings that causes a nil return:

timezone - Asia/Muscat

local - en_GB

string - "2016-12-18 08:31:43"

But when I run this in playground I get a valid date:

let f = DateFormatter.init()
f.dateFormat = "yyyy-MM-dd HH:mm:ss"
f.locale = Locale.init(identifier: "en_GB")
f.timeZone = TimeZone.init(identifier: "Asia/Muscat")

let s = f.date(from: "2016-12-18 08:31:43")

"Dec 18, 2016, 6:31 AM"

What causes the DateFromatter to return nil ?

David Ben Ari
  • 2,259
  • 3
  • 21
  • 40
  • 1
    Try this: http://stackoverflow.com/questions/40692378/swift-3-dateformatter-doesnt-return-date-for-hhmmss. – Martin R Dec 18 '16 at 09:21
  • @MartinR, I have tried overriding the Local incase of a failure, with the "en_US_POSIX" (and also "en_US") Local, and try to format, and yet again I get nil. – David Ben Ari Dec 18 '16 at 09:42
  • “For some reason *some devices* fail to convert a string to a date.” Does the same device convert other strings successfully? – Anton Strogonoff Dec 18 '16 at 11:42
  • I don't think so. I tracked those failures through an analytics sdk, i didn't track successes. – David Ben Ari Dec 18 '16 at 11:48
  • I can only recommend to use the `getObjectValue` method instead because it will give you the exact error. – Sulthan Dec 18 '16 at 11:52
  • If the same device doesn’t convert other strings then it’s foolish to assume it’s region-specific and discard potential implementation quirks in specific OS version. – Anton Strogonoff Dec 18 '16 at 11:55
  • @Tony I'm not discarding any potential anything. I'm willing to try and investigate any path in order to finally understand this. I've been tracking those failures for a few months already, and been trying any implementation quirk I've found on SO with no success. – David Ben Ari Dec 18 '16 at 12:14

1 Answers1

7

If you’re showing your date to the user, don’t set fixed date format string. If you are using fixed-format dates, fix your locale first.

For more details, see Technical Q&A QA1480 titled “NSDateFormatter and Internet Dates”. Below are relevant excerpts (formatting mine):

Q: I'm using NSDateFormatter to parse an Internet-style date, but this fails for some users in some regions. I've set a specific date format string; shouldn't that force NSDateFormatter to work independently of the user's region settings?

A: No. While setting a date format string will appear to work for most users, it's not the right solution to this problem. There are many places where format strings behave in unexpected ways. (…)

If you're working with user-visible dates, you should avoid setting a fixed date format string because it's very hard to predict how your format string will be expressed in all possible user configurations. Rather, you should limit yourself to setting date and time styles (via NSDateFormatter.dateStyle and NSDateFormatter.timeStyle) or generate your date format string from a template (using NSDateFormatter.setLocalizedDateFormatFromTemplate(String)).

On the other hand, if you're working with fixed-format dates, you should first set the locale of the date formatter to something appropriate for your fixed format. In most cases the best locale to choose is "en_US_POSIX", a locale that's specifically designed to yield US English results regardless of both user and system preferences.

Community
  • 1
  • 1
Anton Strogonoff
  • 32,294
  • 8
  • 53
  • 61
  • The used fixed format has no problem with locales. The numbers are the same in the locales. – Sulthan Dec 18 '16 at 11:55
  • 1
    @Sulthan depending on user settings NSDateFormatter will rewrite the format string you set, and if user sets custom calendar then the formatter will treat date string in terms of that calendar—and those are just the two examples of what can go wrong. What am I missing? – Anton Strogonoff Dec 18 '16 at 12:00
  • I am working with fixed-format dates. I get them from my server with a fixed format no matter what. You can see that I included an example of a failed case with the following string: "2016-12-18 08:31:43". I also tried to override the local to en_US_POSIX, and it didn't help. the formatter returned – David Ben Ari Dec 18 '16 at 12:02
  • @DavidBenAri If you have read the Q&A and you have corrected your code in accordance with its recommendations and it didn’t help then I can give no further advice given the information available. – Anton Strogonoff Dec 18 '16 at 12:05
  • 4
    OK!!! I think I've found it. I read right through the QA without realising that the order of the settings matters: **Once you've set "en_US_POSIX" as the locale of the date formatter, you can then set the date format string and the date formatter will behave consistently for all users.** – David Ben Ari Dec 18 '16 at 12:28
  • @DavidBenAri yeah, apparently it checks the locale in dateFormat setter. I’d consider using [`setLocalizedDateFormatFromTemplate`](https://developer.apple.com/reference/foundation/dateformatter/1417087-setlocalizeddateformatfromtempla) anyway, like Apple suggests in [docs for `dateFormat` property](https://developer.apple.com/reference/foundation/dateformatter/1413514-dateformat). Docs for `setLocalizedDateFormatFromTemplate` even have a big note that you should set locale first. Seems like a friendlier way to specify format. – Anton Strogonoff Dec 18 '16 at 13:07