1

I've come across a bit of peculiarity, and I'm not sure why it's happening or how to deal with it.

let formatter = DateFormatter()
formatter.dateFormat = "h:mma"
let timeString = "8:00am"
let date = formatter.date(from: timeString)!

This code works if the user has their time set to use a 12 hour clock. If they have their device set to a 24 hour clock, it crashes.

How do I make make it work independent of the user's settings?

Moin Shirazi
  • 4,372
  • 2
  • 26
  • 38
Erik
  • 2,299
  • 4
  • 18
  • 23

2 Answers2

4

You will have to change the locale to the standard POSIX locale:

formatter.locale = Locale(identifier: "en_US_POSIX")

See the technical note QA1480:

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.

Note that it's a bad practice to enforce a specific time format if you are not parsing/encoding data. If you want to show formatted time to users, a much better solutions is to use the user defined formatting:

let formatter = DateFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .short
Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • 1
    *"It's a bad practice to enforce a specific time format (if you are not parsing/encoding data)."* ... the question appears to be "How do I parse this data," in which case, the correct answer ***is*** to use `.locale`. The "better solution" - in this case - fails. – DonMag Apr 17 '17 at 13:12
  • @DonMag I don't actually see anything there about parsing but I will change the tone of my answer a bit. – Sulthan Apr 17 '17 at 13:14
  • Yeah, this is specifically for parsing data of predetermined format from a server, so I feel comfortable going with this solution. Thank you! – Erik Apr 17 '17 at 13:14
  • By the way, in Swift 3 it is now `formatter.locale = Locale(identifier: "en_US_POSIX")`. – Erik Apr 17 '17 at 13:16
  • 1
    @Erik I recommend to read the technical note above. It's good to remember that you should always set the locale when parsing because otherwise you can crash into issues with calendars and other locale specific things. – Sulthan Apr 17 '17 at 13:17
  • i find this honestly a bit strange, how apple is handling this. we use this code to generate a Date object so that we can compare it with other Date objects. dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" return dateFormatter.date(from: "2020-08-01 01:00:00")! this crashes based on user 24h settings. this makes no sense! the strings come from server and are in (almost) iso format, i should be able to process it regardless of user time settings. – memical Oct 29 '20 at 10:28
  • @memical While I agree with you that what Apple does is strange (although I see the reasoning behind it), encoding data to `String` just to compare dates for equality is significantly worse. That's just wrong. – Sulthan Oct 29 '20 at 10:46
  • the code that i pasted parses the string and converts it to a Date object to compare it. the formater code also specifies HH, which should work in 24h format regardless of the user's settings – memical Oct 29 '20 at 12:30
0

try this code, you need to set timezone for your date,

let formatter = DateFormatter()
formatter.dateFormat = "h:mma"
formatter.timeZone = TimeZone.init(identifier: "UTC")
let timeString = "8:00am"
let date = formatter.date(from: timeString)!

print(date)
Patel Jigar
  • 2,141
  • 1
  • 23
  • 30