Under iOS 7 or 8, the stock Calendar app does something that I have been unable to figure out.
Under some locales, such as en_US
, the Calendar app shows the short (3-letter) month names.
Under other locales, such as de_DE
, the Calendar app shows the full month names. Interestingly, the locale en_DE
shows the short month names so it seems to be tied to the language more than the region format.
What I can't figure out is how to know which month format to use.
Regardless of my device's locale, NSDateFormatter standaloneShortMonthSymbols
gives me the 3-letter month names and NSDateFormatter standaloneMonthSymbols
gives me the full month names.
Is also tried:
NSString *monthformat = [NSDateFormatter dateFormatFromTemplate:@"LLL" options:0 locale:[NSLocale currentLocale]];
and that gives back the same LLL
for both en_US
and de_DE
.
Looking at NSLocale
there doesn't appear to be any value that determines whether to use short or full month names.
There doesn't appear to be anything in NSCalendar
, NSDateFormatter
, or NSLocale
to help determine which month format to use.
Does anyone have any idea how to make this determination?
Update:
I thought I found a solution but it doesn't work for all locales that I tried. I ran the following code with various locales to see if I could find anything in common between locales that show the short and long months names in the Calendar app:
NSLocale *locale = [NSLocale currentLocale];
NSString *locid = [locale localeIdentifier];
NSLog(@"Locale = %@", locid);
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSLog(@"monthSymbols = %@", [formatter monthSymbols]);
NSLog(@"shortMonthSymbols = %@", [formatter shortMonthSymbols]);
NSLog(@"veryShortMonthSymbols = %@", [formatter veryShortMonthSymbols]);
NSLog(@"monthStandaloneSymbols = %@", [formatter standaloneMonthSymbols]);
NSLog(@"shortStandaloneMonthSymbols = %@", [formatter shortStandaloneMonthSymbols]);
NSLog(@"veryShortStandaloneMonthSymbols = %@", [formatter veryShortStandaloneMonthSymbols]);
NSDate *date = [NSDate date];
[formatter setDateStyle:NSDateFormatterShortStyle];
NSLog(@"short date style: %@", [formatter stringFromDate:date]);
[formatter setDateStyle:NSDateFormatterMediumStyle];
NSLog(@"medium date style: %@", [formatter stringFromDate:date]);
[formatter setDateStyle:NSDateFormatterLongStyle];
NSLog(@"long date style: %@", [formatter stringFromDate:date]);
[formatter setDateStyle:NSDateFormatterFullStyle];
NSLog(@"full date style: %@", [formatter stringFromDate:date]);
[formatter setDateStyle:NSDateFormatterNoStyle];
[formatter setDateFormat:@"M"];
NSLog(@"M date format: %@", [formatter stringFromDate:date]);
[formatter setDateFormat:@"MM"];
NSLog(@"MM date format: %@", [formatter stringFromDate:date]);
[formatter setDateFormat:@"MMM"];
NSLog(@"MMM date format: %@", [formatter stringFromDate:date]);
[formatter setDateFormat:@"MMMM"];
NSLog(@"MMMM date format: %@", [formatter stringFromDate:date]);
[formatter setDateFormat:@"MMMMM"];
NSLog(@"MMMMM date format: %@", [formatter stringFromDate:date]);
[formatter setDateFormat:@"L"];
NSLog(@"L date format: %@", [formatter stringFromDate:date]);
[formatter setDateFormat:@"LL"];
NSLog(@"LL date format: %@", [formatter stringFromDate:date]);
[formatter setDateFormat:@"LLL"];
NSLog(@"LLL date format: %@", [formatter stringFromDate:date]);
[formatter setDateFormat:@"LLLL"];
NSLog(@"LLLL date format: %@", [formatter stringFromDate:date]);
[formatter setDateFormat:@"LLLLL"];
NSLog(@"LLLLL date format: %@", [formatter stringFromDate:date]);
I had tested with en_US
, en_GB
, es_ES
, de_DE
, fr_FR
, and it_IT
. The French and German locales show the full month name in the Calendar app while the rest show the short name.
The one thing that looked promising with the test code is that only the French and German locales have a period at the end of the shortMonthSymbols
.
So then I ran the following code to find all locales that use punctuation in the short month symbols and those that don't:
NSMutableArray *hasDot = [[NSMutableArray alloc] init];
NSMutableArray *noDot = [[NSMutableArray alloc] init];
NSCharacterSet *letters = [NSCharacterSet letterCharacterSet];
NSArray *locales = [NSLocale availableLocaleIdentifiers];
for (NSString *locid in locales) {
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:locid];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:locale];
NSArray *shortNames = [formatter shortMonthSymbols];
//NSLog(@"locale: %@, short names: %@", locid, shortNames[10]);
NSString *nov = shortNames[10];
unichar char1 = [nov characterAtIndex:0];
unichar charN = [nov characterAtIndex:nov.length - 1];
if ([letters characterIsMember:char1] && [letters characterIsMember:charN]) {
[noDot addObject:locid];
} else {
[hasDot addObject:locid];
}
}
NSLog(@"no dot: %@", [noDot sortedArrayUsingSelector:@selector(compare:)]);
NSLog(@"has dot: %@", [hasDot sortedArrayUsingSelector:@selector(compare:)]);
Scanning through the results I saw that the Dutch locales used a period in the short month symbols. But a quick test of the Calendar app revealed that the Calendar app showed short month names when the device was set to Dutch (nl_NL
). Ugh.
Update 2:
I've tested a few more locales. The following show long month names:
fr_FR, de_DE, ru_RU, sv_SE (actually all locales for each of these languages)
the following (and I'm sure many more) show the short month:
en_US, en_GB, es_ES, it_IT, nl_NL, ca_ES, uk_UA, ro_RO (actually all locales for each of these languages)
Once every so often, there comes a question worth looking into. Rick, for you I debugged the Calendar app (can be done using attaching to MobileCal process). It all comes down to
EventKitUI`CurrentLocaleRequiresUnabbrevatedMonthNames
which answers the desired question.Let's look at its disassembly:
As you can see, it creates an array of locales that require unabbreviated month names. It then compares if the current locale is one of these locales.
Hardcoded in the code.
For abbreviated months, it uses the
LLL
format (as seen inEventKitUI`CalStringForMonth
), and for unabbreviated months, it uses theLLLL
format (as seen inEventKitUI`CalLongStringForMonth
).Cheers