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.


The date format used in the menu bar on Mac OS X is contained in the file ~/Library/Preferences/com.apple.menuextra.clock.plist. On my system (en_US locale) it looks like this for non-24 hour time:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>DateFormat</key>
    <string>EEE h:mm a</string>
    <key>FlashDateSeparators</key>
    <false/>
    <key>IsAnalog</key>
    <false/>
</dict>
</plist>

and like this for 24-hour time:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>DateFormat</key>
    <string>EEE H:mm</string>
    <key>FlashDateSeparators</key>
    <false/>
    <key>IsAnalog</key>
    <false/>
</dict>
</plist>

You can retrieve the format string using defaults read com.apple.menuextra.clock DateFormat from the command line or NSUserDefaults from Obj-C or Swift. You can then check if the format string contains a. If it does the clock is not set to 24-hour time.


Use this extension

extension Locale {
    static var is24Hour: Bool {
        let dateFormat = DateFormatter.dateFormat(fromTemplate: "j", options: 0, locale: Locale.current)!
        return dateFormat.firstIndex(of: "a") == nil
    }
}

Free to use anywhere

if Locale.is24Hour {
    // Show 24 hour time
} else {
    // Show 12 hour time
}

Swift 4

Here's a swift 4 interpretation of the accepted answer:

func is24Hour() -> Bool {
    let dateFormat = DateFormatter.dateFormat(fromTemplate: "j", options: 0, locale: Locale.current)!

    return dateFormat.firstIndex(of: "a") == nil
}

Usage:

if is24Hour() {
    // should show 24 hour time
} else {
    // should show 12 hour time
}