Nsdateformatter Detect 24-Hour Clock in Os X and iOS

NSDateFormatter detect 24-hour clock in OS X and iOS

The date template function has a neat trick. There is a template specifier j which will turn into an hour format depending if the locale uses 12 or 24 hour format. It'll turn into something like h a for 12 hour (en_US in this case) or HH for 24 hour format (en_GB).

Then you just have to check if the date format contains a

//let locale = NSLocale(localeIdentifier: "de_DE")
//let locale = NSLocale(localeIdentifier: "en_US")
//let locale = NSLocale(localeIdentifier: "en_GB")
let locale = NSLocale.currentLocale()

let dateFormat = NSDateFormatter.dateFormatFromTemplate("j", options: 0, locale: locale)!

if dateFormat.rangeOfString("a") != nil {
println("12 hour")
}
else {
println("24 hour")
}

This should take format overwrites into account as well.

This is similar to your check, but you should not try to check for AM or PM. These are the english versions, there are many more. For example in Germany if you force a 12 hour format iOS uses nachm. and vorm.. The correct way is to check the format for a.

Detect iPhone 24-Hour time setting

  • one
  • two
  • three

and there's probably many, many more...

Why does the following time sorting code break for devices using a 24-hour clock?

An approach...

Since you have two possible formats, you need two formatters...

let format12 = DateFormatter()
format12.dateFormat = "h:mm a"
// Fix the possible formatting and avoid issues with the local and parsing
format12.locale = Locale(identifier: "en_US_POSIX")

let format24 = DateFormatter()
format24.dateFormat = "H:mm"
format24.locale = Locale(identifier: "en_US_POSIX")

Now you need to parse your input into date values...

var items: [String] = ["1:00 PM", "4:00 PM", "13:00", "16:00"]

var dates: [Date?] = items.map {
if let value = format24.date(from: $0) { return value }
else if let value = format12.date(from: $0) { return value }
return nil
}

And sort it...

dates.sort {
guard let lhs = $0, let rhs = $1 else { return true }
return lhs < rhs
}

Now, the above anticipates that some values may be nil and takes appropriate action.

Now you could, instead, use compactMap to remove the possible nil values, for example...

var dates: [Date] = items.compactMap {
if let value = format24.date(from: $0) { return value }
else if let value = format12.date(from: $0) { return value }
return nil
}

dates.sort {
guard let lhs = $0, let rhs = $1 else { return true }
return lhs < rhs
}

dates.sort { $0 < $1 }

I dumped all of this into Playground and have no issues

Side note...

If you are getting nil values with either of the two formatters, then you need to take a closer look at the values and determine how they are not fitting the pattern of the formatters and take appropriate actions to correct it

DateFormatter behaves different based on user time settings

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

Swift converting NSDate to 24h Format fails on Device

QA1480: set yourself to be a a formatter's locale to en_US_POSIX. Otherwise your device's locale will affect date patterns.



Related Topics



Leave a reply



Submit