知道何时使用短月或全月名称

时间:2014-11-13 00:04:37

标签: ios objective-c nsdateformatter nslocale

在iOS 7或8下,库存日历应用程序执行了一些我无法弄清楚的事情。

在某些区域设置(例如en_US)下,日历应用会显示短(3个字母)的月份名称。

在其他区域设置(例如de_DE)下,日历应用会显示完整的月份名称。有趣的是,语言环境en_DE显示了短月份名称,因此它似乎与语言相关联而不是区域格式。

我无法弄清楚如何知道使用哪种月份格式。

无论我的设备的区域设置如何,NSDateFormatter standaloneShortMonthSymbols都会为我提供3个字母的月份名称,NSDateFormatter standaloneMonthSymbols会为我提供完整的月份名称。

也尝试过:

NSString *monthformat = [NSDateFormatter dateFormatFromTemplate:@"LLL" options:0 locale:[NSLocale currentLocale]];

并为LLLen_US提供相同的de_DE

查看NSLocale,似乎没有任何值可以决定是使用短月或全月名称。

NSCalendarNSDateFormatterNSLocale中似乎没有任何内容可帮助您确定要使用的月份格式。

有没有人知道如何做出这个决定?

更新

我以为我找到了一个解决方案,但它并不适用于我尝试过的所有语言环境。我使用各种区域设置运行以下代码,以查看是否可以在日历应用程序中找到显示短月和长月名称的区域设置之间的任何共同点:

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]);

我使用en_USen_GBes_ESde_DEfr_FRit_IT进行了测试。法语和德语语言环境在日历应用程序中显示完整的月份名称,而其余的显示短名称。

使用测试代码看起来很有希望的一件事是,只有法语和德语语言环境在shortMonthSymbols的末尾有句号。

然后我运行以下代码来查找在短月符号中使用标点符号的所有语言环境以及那些不使用标点符号的语言环境:

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:)]);

扫描结果我看到荷兰语语言环境在短月符号中使用了一段时间。但是对Calendar应用程序的快速测试显示,当设备设置为Dutch(nl_NL)时,Calendar应用程序显示短月份名称。啊。

更新2:

我已经测试了一些其他语言环境。以下显示长月名称:

fr_FR,de_DE,ru_RU,sv_SE(实际上是每种语言的所有语言环境)

以下(我还有更多)显示短月:

en_US,en_GB,es_ES,it_IT,nl_NL,ca_ES,uk_UA,ro_RO(实际上是每种语言的所有语言环境)

1 个答案:

答案 0 :(得分:18)

每隔一段时间,就会有一个值得研究的问题。瑞克,为你调试了日历应用程序(可以使用附加到MobileCal进程完成)。这一切都归结为EventKitUI`CurrentLocaleRequiresUnabbrevatedMonthNames,它回答了所需的问题。

让我们来看看它的反汇编:

EventKitUI`CurrentLocaleRequiresUnabbrevatedMonthNames:
0x102c6bec7:  pushq  %rbp
0x102c6bec8:  movq   %rsp, %rbp
0x102c6becb:  pushq  %r15
0x102c6becd:  pushq  %r14
0x102c6becf:  pushq  %rbx
0x102c6bed0:  subq   $0xb8, %rsp
0x102c6bed7:  movq   0x14a3aa(%rip), %r15      ; (void *)0x0000000104e93070: __stack_chk_guard
0x102c6bede:  movq   (%r15), %rax
0x102c6bee1:  movq   %rax, -0x20(%rbp)
0x102c6bee5:  cmpq   $0x0, 0x1c01fb(%rip)      ; CurrentLocaleRequiresUnabbrevatedMonthNames.usesFullLengthMonthNames + 6
0x102c6beed:  je     0x102c6beff               ; CurrentLocaleRequiresUnabbrevatedMonthNames + 56
0x102c6beef:  movb   0x1c01eb(%rip), %al       ; CurrentLocaleRequiresUnabbrevatedMonthNames.hasChecked
0x102c6bef5:  xorb   $0x1, %al
0x102c6bef7:  testb  $0x1, %al
0x102c6bef9:  je     0x102c6c0d6               ; CurrentLocaleRequiresUnabbrevatedMonthNames + 527
0x102c6beff:  movq   0x1b583a(%rip), %rdi      ; (void *)0x00000001025dae58: NSLocale
0x102c6bf06:  movq   0x1aef23(%rip), %rsi      ; "currentLocale"
0x102c6bf0d:  movq   0x14a524(%rip), %r14      ; (void *)0x0000000104945000: objc_msgSend
0x102c6bf14:  callq  *%r14
0x102c6bf17:  movq   %rax, %rdi
0x102c6bf1a:  callq  0x102d29920               ; symbol stub for: objc_retainAutoreleasedReturnValue
0x102c6bf1f:  movq   %rax, %rbx
0x102c6bf22:  movq   0x14a227(%rip), %rax      ; (void *)0x00000001025a3cd8: NSLocaleLanguageCode
0x102c6bf29:  movq   (%rax), %rdx
0x102c6bf2c:  movq   0x1ae12d(%rip), %rsi      ; "objectForKey:"
0x102c6bf33:  movq   %rbx, %rdi
0x102c6bf36:  callq  *%r14
0x102c6bf39:  movq   %rax, %rdi
0x102c6bf3c:  callq  0x102d29920               ; symbol stub for: objc_retainAutoreleasedReturnValue
0x102c6bf41:  movq   %rax, %r14
0x102c6bf44:  movq   %rbx, %rdi
0x102c6bf47:  callq  *0x14a4f3(%rip)           ; (void *)0x00000001049429b0: objc_release
0x102c6bf4d:  movq   0x1c0194(%rip), %rdi      ; __languagesRequiringUnabbreviatedMonthNames
0x102c6bf54:  testq  %rdi, %rdi
0x102c6bf57:  jne    0x102c6c0b0               ; CurrentLocaleRequiresUnabbrevatedMonthNames + 489
0x102c6bf5d:  leaq   0x15425c(%rip), %rax      ; @"ru"
0x102c6bf64:  movq   %rax, -0xd0(%rbp)
0x102c6bf6b:  leaq   0x1524ce(%rip), %rax      ; @"de"
0x102c6bf72:  movq   %rax, -0xc8(%rbp)
0x102c6bf79:  leaq   0x154260(%rip), %rax      ; @"fr"
0x102c6bf80:  movq   %rax, -0xc0(%rbp)
0x102c6bf87:  leaq   0x154272(%rip), %rax      ; @"fi"
0x102c6bf8e:  movq   %rax, -0xb8(%rbp)
0x102c6bf95:  leaq   0x154284(%rip), %rax      ; @"pt"
0x102c6bf9c:  movq   %rax, -0xb0(%rbp)
0x102c6bfa3:  leaq   0x154296(%rip), %rax      ; @"no"
0x102c6bfaa:  movq   %rax, -0xa8(%rbp)
0x102c6bfb1:  leaq   0x1542a8(%rip), %rax      ; @"nb"
0x102c6bfb8:  movq   %rax, -0xa0(%rbp)
0x102c6bfbf:  leaq   0x1542ba(%rip), %rax      ; @"nn"
0x102c6bfc6:  movq   %rax, -0x98(%rbp)
0x102c6bfcd:  leaq   0x1542cc(%rip), %rax      ; @"sv"
0x102c6bfd4:  movq   %rax, -0x90(%rbp)
0x102c6bfdb:  leaq   0x1542de(%rip), %rax      ; @"he"
0x102c6bfe2:  movq   %rax, -0x88(%rbp)
0x102c6bfe9:  leaq   0x1542f0(%rip), %rax      ; @"th"
0x102c6bff0:  movq   %rax, -0x80(%rbp)
0x102c6bff4:  leaq   0x154305(%rip), %rax      ; @"hi"
0x102c6bffb:  movq   %rax, -0x78(%rbp)
0x102c6bfff:  leaq   0x15431a(%rip), %rax      ; @"bn"
0x102c6c006:  movq   %rax, -0x70(%rbp)
0x102c6c00a:  leaq   0x15432f(%rip), %rax      ; @"mr"
0x102c6c011:  movq   %rax, -0x68(%rbp)
0x102c6c015:  leaq   0x154344(%rip), %rax      ; @"ur"
0x102c6c01c:  movq   %rax, -0x60(%rbp)
0x102c6c020:  leaq   0x154359(%rip), %rax      ; @"te"
0x102c6c027:  movq   %rax, -0x58(%rbp)
0x102c6c02b:  leaq   0x15436e(%rip), %rax      ; @"ta"
0x102c6c032:  movq   %rax, -0x50(%rbp)
0x102c6c036:  leaq   0x154383(%rip), %rax      ; @"gu"
0x102c6c03d:  movq   %rax, -0x48(%rbp)
0x102c6c041:  leaq   0x154398(%rip), %rax      ; @"kn"
0x102c6c048:  movq   %rax, -0x40(%rbp)
0x102c6c04c:  leaq   0x1543ad(%rip), %rax      ; @"ml"
0x102c6c053:  movq   %rax, -0x38(%rbp)
0x102c6c057:  leaq   0x1543c2(%rip), %rax      ; @"ne"
0x102c6c05e:  movq   %rax, -0x30(%rbp)
0x102c6c062:  leaq   0x1543d7(%rip), %rax      ; @"pa"
0x102c6c069:  movq   %rax, -0x28(%rbp)
0x102c6c06d:  movq   0x1b55ec(%rip), %rdi      ; (void *)0x00000001025d9cd8: NSArray
0x102c6c074:  movq   0x1ae5cd(%rip), %rsi      ; "arrayWithObjects:count:"
0x102c6c07b:  leaq   -0xd0(%rbp), %rdx
0x102c6c082:  movl   $0x16, %ecx
0x102c6c087:  callq  *0x14a3ab(%rip)           ; (void *)0x0000000104945000: objc_msgSend
0x102c6c08d:  movq   %rax, %rdi
0x102c6c090:  callq  0x102d29920               ; symbol stub for: objc_retainAutoreleasedReturnValue
0x102c6c095:  movq   0x1c004c(%rip), %rdi      ; __languagesRequiringUnabbreviatedMonthNames
0x102c6c09c:  movq   %rax, 0x1c0045(%rip)      ; __languagesRequiringUnabbreviatedMonthNames
0x102c6c0a3:  callq  *0x14a397(%rip)           ; (void *)0x00000001049429b0: objc_release
0x102c6c0a9:  movq   0x1c0038(%rip), %rdi      ; __languagesRequiringUnabbreviatedMonthNames
0x102c6c0b0:  movq   0x1ae6c1(%rip), %rsi      ; "containsObject:"
0x102c6c0b7:  movq   %r14, %rdx
0x102c6c0ba:  callq  *0x14a378(%rip)           ; (void *)0x0000000104945000: objc_msgSend
0x102c6c0c0:  movb   %al, 0x1c001b(%rip)       ; CurrentLocaleRequiresUnabbrevatedMonthNames.usesFullLengthMonthNames
0x102c6c0c6:  movb   $0x1, 0x1c0013(%rip)      ; __overlayCalendarGeneration + 7
0x102c6c0cd:  movq   %r14, %rdi
0x102c6c0d0:  callq  *0x14a36a(%rip)           ; (void *)0x00000001049429b0: objc_release
0x102c6c0d6:  movb   0x1c0005(%rip), %al       ; CurrentLocaleRequiresUnabbrevatedMonthNames.usesFullLengthMonthNames
0x102c6c0dc:  movq   (%r15), %rcx
0x102c6c0df:  cmpq   -0x20(%rbp), %rcx
0x102c6c0e3:  jne    0x102c6c0f3               ; CurrentLocaleRequiresUnabbrevatedMonthNames + 556
0x102c6c0e5:  addq   $0xb8, %rsp
0x102c6c0ec:  popq   %rbx
0x102c6c0ed:  popq   %r14
0x102c6c0ef:  popq   %r15
0x102c6c0f1:  popq   %rbp
0x102c6c0f2:  retq   
0x102c6c0f3:  callq  0x102d29a1c               ; symbol stub for: __stack_chk_fail

如您所见,它创建了一系列需要未缩写月份名称的语言环境。然后,它会比较当前区域设置是否是这些区域设置之一。

代码中的硬编码。

对于缩写月份,它使用LLL格式(如EventKitUI`CalStringForMonth中所示),对于未缩短的月份,它使用LLLL格式(如EventKitUI`CalLongStringForMonth中所示) )。

干杯