Is there any way to detect if the current device of the app uses 12h our 24h format, so that I can use one NSDateFormatter for 12h and one for 24h depending on the users language/loaction setting? Just Like the UIDatePicker detects and shows the AM/PM picker if it is 12h format.
-
@progrmr that is definitely a good solution for determining if the 24 hour clock is set or not but it depends on the Date Formatters behavior. The OP wanted this information to format a string using the date formatter so that solution would involve adding a class category, creating a date formatter, converting a date to a string, searching the string twice for AM/PM symbols, then branching your code to format using either 12 hour or 24 hour format when it already does that for you. – Joe Sep 16 '11 at 20:18
-
1@Joe I know that, but sometimes you need to know for other reasons, like to put the "AM" in a separate UILabel with a different font, the OP wasn't clear exactly why he wanted to know. – progrmr Sep 16 '11 at 23:05
6 Answers
I figured it out, its pretty easy. I just added this code to viewDidLoad
:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[NSLocale currentLocale]];
[formatter setDateStyle:NSDateFormatterNoStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
NSString *dateString = [formatter stringFromDate:[NSDate date]];
NSRange amRange = [dateString rangeOfString:[formatter AMSymbol]];
NSRange pmRange = [dateString rangeOfString:[formatter PMSymbol]];
BOOL is24h = (amRange.location == NSNotFound && pmRange.location == NSNotFound);
[formatter release];
NSLog(@"%@\n",(is24h ? @"YES" : @"NO"));
And it perfectly returns YES
or NO
depending on the locale.

- 9,274
- 12
- 59
- 88
-
3This only works if the local calendar uses the same format as the phone does but on iOS you can specifically set the time format which could make it different from what is used in the local calendar. – yoeriboven Oct 10 '16 at 10:19
And here is a Swift 3.0 updated version
func using12hClockFormat() -> Bool {
let formatter = DateFormatter()
formatter.locale = Locale.current
formatter.dateStyle = .none
formatter.timeStyle = .short
let dateString = formatter.string(from: Date())
let amRange = dateString.range(of: formatter.amSymbol)
let pmRange = dateString.range(of: formatter.pmSymbol)
return !(pmRange == nil && amRange == nil)
}

- 3,211
- 22
- 36
this is swift solution that worked for me, those two above did not.
let dateString: String = DateFormatter.dateFormat(
fromTemplate: "j", options: 0,
locale: Locale.current
)!
if(dateString.contains("a")){
// 12 h format
return true
}else{
// 24 h format
return false
}

- 1,157
- 12
- 18

- 546
- 1
- 10
- 16
-
-
1@superpuccio read more here http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns – beowulf Feb 02 '23 at 13:25
For Swift 5.3. Tested on Xcode 12.
func is12hClockFormat() -> Bool {
let formatString = DateFormatter.dateFormat(
fromTemplate: "j",
options: 0,
locale: Locale.current
)!
return formatString.contains("a")
}
This uses a special date template string called "j". According to the ICU Spec, "j"...
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).
That last sentence is important. It "is the only way to have a skeleton request a locale's preferred time cycle type". Since NSDateFormatter and NSCalendar are built on the ICU library, the same holds true here.
Collected from https://stackoverflow.com/a/11660380/3428146

- 1,157
- 12
- 18
Here is the Swift version:
func using12hClockFormat() -> Bool {
let formatter = NSDateFormatter()
formatter.locale = NSLocale.currentLocale()
formatter.dateStyle = NSDateFormatterStyle.NoStyle
formatter.timeStyle = NSDateFormatterStyle.ShortStyle
let dateString = formatter.stringFromDate(NSDate())
let amRange = dateString.rangeOfString(formatter.AMSymbol)
let pmRange = dateString.rangeOfString(formatter.PMSymbol)
return !(pmRange == nil && amRange == nil)
}

- 4,150
- 4
- 35
- 67
-
You are using the ternary operator as a NOT, which just makes it harder to read. Return line should be this `return !(pmRange == nil && amRange == nil)` – EmilioPelaez Sep 27 '16 at 14:57
-
1wouldn't it be easier (more readable) to `return pmRange != nil || amRange != nil` ? – micromanc3r Mar 25 '19 at 15:01
Objective C category NSDate+Extensions
:
@import Foundation;
@interface NSDate (Extensions)
- (NSString *)getTimeString;
@end
#import "NSDate+Extensions.h"
@implementation NSDate (Extensions)
- (NSString *)getTimeString
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
if ([self isTwelveHourDateFormat]) {
[formatter setDateFormat:@"hh:mm\ndd MMM"];
}
else {
[formatter setDateFormat:@"HH:mm\ndd MMM"];
}
return [formatter stringFromDate:self];
}
- (BOOL)isTwelveHourDateFormat
{
NSString *dateFormat = [NSDateFormatter dateFormatFromTemplate:@"j" options:0 locale:[NSLocale currentLocale]];
return [dateFormat containsString:@"a"];
}
@end

- 15,320
- 6
- 84
- 70