9

I'm using a UIDatePicker to select a time. I am also customising the background of the picker, however I need 2 different images depending on whether the user is using 12 hour mode (which displays AM/PM column) or 24 hour mode. How can I detect the users setting for the 12/24 hour time?

Thanks

Darren
  • 10,182
  • 20
  • 95
  • 162

3 Answers3

39

Even shorter than the others:

NSString *format = [NSDateFormatter dateFormatFromTemplate:@"j" options:0 locale:[NSLocale currentLocale]];
BOOL is24Hour = ([format rangeOfString:@"a"].location == NSNotFound);

Explanation

The string formatting character to represent the am/pm symbol is "a", as documented in Unicode Locale Markup Language – Part 4: Dates.

The same document also explains the special template symbol "j":

This is a special-purpose symbol. It must not occur in pattern or skeleton data. Instead, it is reserved for use in skeletons passed to APIs doing flexible date pattern generation. In such a context, it requests the preferred hour format for the locale (h, H, K, or k), as determined by whether h, H, K, or k is used in the standard short time format for the locale. In the implementation of such an API, 'j' must be replaced by h, H, K, or k before beginning a match against availableFormats data. Note that use of 'j' in a skeleton passed to an API is the only way to have a skeleton request a locale's preferred time cycle type (12-hour or 24-hour).

The NSString method dateFormatFromTemplate:options:locale: is described in Apple's NSDateFormatter documentation:

Returns a localized date format string representing the given date format components arranged appropriately for the specified locale.

So, what that method will do is turn the @"j" you pass in as a template in to a format string suitable for NSDateFormatter. If this string contains the am / pm symbol @"a" in it anywhere, then you know the locale (and other user settings being interrogated by the OS for you) wants am / pm to be displayed.

Benjohn
  • 13,228
  • 9
  • 65
  • 127
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • 1
    I was totally about to down vote your answer as not working, until I read it a lot closer. That's clever. Nice one! – Benjohn Feb 15 '14 at 15:29
  • Just to add that this will not work on the simulator. – GuybrushThreepwood Jul 14 '15 at 09:11
  • 1
    Unfortunately, I don't believe this will work in 10.14 unless your application is localized in the user’s language. The system now does what iOS does and returns currentLocale only in a language that your app is localized in, which will not actually match the user locale. – Peter N Lewis Apr 25 '19 at 08:12
  • @PeterNLewis Do you know that it is not working? Or is that just a guess? I do not have an Apple Developer Account and can not test it on my iPhone – juliushuck Aug 27 '20 at 17:53
  • Yes, I know it does not work. NSDateFormatter will use the users locale in formatting dates, and so the result may not be "am/pm" depending on the language and the user locale settings. – Peter N Lewis Aug 28 '20 at 11:33
7

Swift (3.x) version of two most popular solutions in form of Date extension :

extension Date {

    static var is24HoursFormat_1 : Bool  {
        let dateString = Date.localFormatter.string(from: Date())

        if dateString.contains(Date.localFormatter.amSymbol) || dateString.contains(Date.localFormatter.pmSymbol) {
            return false
        }

        return true
    }

    static var is24HoursFormat_2 : Bool {
        let format = DateFormatter.dateFormat(fromTemplate: "j", options: 0, locale: Locale.autoupdatingCurrent)
        return !format!.contains("a")
    }

    private static let localFormatter : DateFormatter = {
        let formatter = DateFormatter()

        formatter.locale    = Locale.autoupdatingCurrent
        formatter.timeStyle = .short
        formatter.dateStyle = .none

        return formatter
    }()
}

Usage :

Date.is24HoursFormat_1
Date.is24HoursFormat_2

Swift (2.0) version of two most popular solutions in form of NSDate extension :

extension NSDate {

    class var is24HoursFormat_1 : Bool  {
        let dateString = NSDate.localFormatter.stringFromDate(NSDate())

        if dateString.containsString(NSDate.localFormatter.AMSymbol) || dateString.containsString(NSDate.localFormatter.PMSymbol) {
            return false
        }

        return true
    }

    class var is24HoursFormat_2 : Bool {
        let format = NSDateFormatter.dateFormatFromTemplate("j", options: 0, locale: NSLocale.autoupdatingCurrentLocale())
        return !format!.containsString("a")
    }

    private static let localFormatter : NSDateFormatter = {
        let formatter = NSDateFormatter()

        formatter.locale    = NSLocale.autoupdatingCurrentLocale()
        formatter.timeStyle = .ShortStyle
        formatter.dateStyle = .NoStyle

        return formatter
    }()
}

Please note that Apple says following on NSDateFormatter (Date Formatters) :

Creating a date formatter is not a cheap operation. If you are likely to use a formatter frequently, it is typically more efficient to cache a single instance than to create and dispose of multiple instances. One approach is to use a static variable.

Thats the reason for static let

Secondly you should use NSLocale.autoupdatingCurrentLocale() ( for is24HoursFormat_1 ), that way you will always get the actual current state.

CryingHippo
  • 5,026
  • 1
  • 28
  • 32
3

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

Community
  • 1
  • 1
patryk
  • 642
  • 1
  • 9
  • 18
  • Wow, thanks. I did a Google search which normally shows Stack Overflow results but I came up completely blank! – Darren Aug 31 '12 at 11:34