23

I would like to check if the user has selected the 12-hour or 24-hour clock as their preference in OS X and iOS. So I would like to detect if the user has done the following:

  • On the Mac, the System Preference is in Date & Time, Use a 24-hour Clock
  • On the iPhone, the Preference is in Settings, General, Date & Time, 24-Hour Time

I currently have the following code but it always returns the time as represented by the 12-hour clock, even if the system preference set by the user is for the 24-hour clock.

let timeFormatter = NSDateFormatter()
timeFormatter.locale = NSLocale.currentLocale()
timeFormatter.dateStyle = NSDateFormatterStyle.NoStyle
timeFormatter.timeStyle = NSDateFormatterStyle.ShortStyle

let ampmtext = timeFormatter.stringFromDate(NSDate())
println(ampmtext)

if ampmtext.rangeOfString("M") != nil {
    println("12-hour clock")
} else {
    println("24-hour clock")
}

I would like to find a solution written in Objective-C and Swift for both the Mac and iPhone that can detect if the device clock displays 24-hour or 12-hour time.

wigging
  • 8,492
  • 12
  • 75
  • 117
  • See [this](http://stackoverflow.com/questions/6613110/what-is-the-best-way-to-deal-with-the-nsdateformatter-locale-feature). It's addressing sort of the opposite of your problem, but it gives you some background. (Though I don't offhand know of a surefire way to explicitly test the 12/24 setting in spite of all the possible locales, etc.) – Hot Licks Jan 27 '15 at 03:50
  • @HotLicks I edited my question. The code works but the error is in how I'm handling the settings on the Mac and how I'm using the iPhone simulator for iOS. – wigging Jan 28 '15 at 01:28
  • When I was looking at the problem I couldn't figure out a way to provoke it on the iPhone simulator -- we had to test with real live phones. (Wasn't worried about OSx.) – Hot Licks Jan 28 '15 at 01:35

4 Answers4

40

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.

Matthias Bauch
  • 89,811
  • 20
  • 225
  • 247
  • I agree, this seems to be a much better approach. One last thing - Is there a way to test this in the iPhone simulator? It looks like you have to run the code on the actual device, but it would be convenient to be able to change the locale to a 24-hour clock in the simulator. – wigging Feb 01 '15 at 00:27
  • As far as I am aware iOS Simulator doesn't support these custom formats. – Matthias Bauch Feb 01 '15 at 13:49
  • Where did you find this `j` specifier? Are there other specifiers like this one? – Wojciech Kulik Jul 19 '23 at 15:42
22

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
}
user10447655
  • 180
  • 2
  • 10
Megagator
  • 416
  • 6
  • 12
5

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
}
Sreekuttan
  • 1,579
  • 13
  • 19
1

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.

sbooth
  • 16,646
  • 2
  • 55
  • 81