问题描述
似乎 NSDateFormatter
有一个功能意外地咬你:如果你做一个简单的固定格式操作,例如:
It seems that NSDateFormatter
has a "feature" that bites you unexpectedly: If you do a simple "fixed" format operation such as:
NSDateFormatter* fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyyMMddHHmmss"];
NSString* dateStr = [fmt stringFromDate:someDate];
[fmt release];
然后它在美国和大多数语言环境中工作正常UNTIL ...某人将手机设置为a 24小时区域将设置中的12/24小时开关设置为12.然后上面开始将AM或PM添加到结果字符串的末尾。
Then it works fine in the US and most locales UNTIL ... someone with their phone set to a 24-hour region sets the 12/24 hour switch in settings to 12. Then the above starts tacking "AM" or "PM" onto the end of the resulting string.
(参见,例如,)
(并参见)
显然苹果公司宣称这是不好 - 按设计划分,他们不会修复它。
Apparently Apple has declared this to be "BAD" -- Broken As Designed, and they aren't going to fix it.
规避是显然是为特定区域设置日期格式化程序的语言环境,通常是美国,但这有点乱:
The circumvention is apparently to set the locale of the date formatter for a specific region, generally the US, but this is a bit messy:
NSLocale *loc = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[df setLocale: loc];
[loc release];
在onsies-twosies中不是太糟糕,但我正在处理大约十个不同的应用程序,我看到的第一个有这个场景的43个实例。
Not too bad in onsies-twosies, but I'm dealing with about ten different apps, and the first one I look at has 43 instances of this scenario.
所以对于宏/重写类/任何最小化改变所有内容的努力的任何聪明的想法,而不是代码模糊不清? (我的第一直觉是使用一个在init方法中设置语言环境的版本来覆盖NSDateFormatter。需要更改两行 - alloc / init行和添加的导入。)
So any clever ideas for a macro/overridden class/whatever to minimize the effort to change everything, without making the code to obscure? (My first instinct is to override NSDateFormatter with a version that would set the locale in the init method. Requires changing two lines -- the alloc/init line and the added import.)
这是我到目前为止所提出的 - 似乎适用于所有情况:
This is what I've come up with so far -- seems to work in all scenarios:
@implementation BNSDateFormatter
-(id)init {
static NSLocale* en_US_POSIX = nil;
NSDateFormatter* me = [super init];
if (en_US_POSIX == nil) {
en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
[me setLocale:en_US_POSIX];
return me;
}
@end
Bounty!
我将奖励给我在周二中午看到的最佳(合法)建议/批评。 [见下文 - 延长期限延长。]
Bounty!
I'll award the bounty to the best (legitimate) suggestion/critique I see by mid-day Tuesday. [See below -- deadline extended.]
重新讨论OMZ的建议,这就是我的意思查找 -
Re OMZ's proposal, here is what I'm finding --
这是类别版本 - h文件:
Here is the category version -- h file:
#import <Foundation/Foundation.h>
@interface NSDateFormatter (Locale)
- (id)initWithSafeLocale;
@end
类别m文件:
#import "NSDateFormatter+Locale.h"
@implementation NSDateFormatter (Locale)
- (id)initWithSafeLocale {
static NSLocale* en_US_POSIX = nil;
self = [super init];
if (en_US_POSIX == nil) {
en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
NSLog(@"Category's locale: %@ %@", en_US_POSIX.description, [en_US_POSIX localeIdentifier]);
[self setLocale:en_US_POSIX];
return self;
}
@end
代码:
NSDateFormatter* fmt;
NSString* dateString;
NSDate* date1;
NSDate* date2;
NSDate* date3;
NSDate* date4;
fmt = [[NSDateFormatter alloc] initWithSafeLocale];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
dateString = [fmt stringFromDate:[NSDate date]];
NSLog(@"dateString = %@", dateString);
date1 = [fmt dateFromString:@"2001-05-05 12:34:56"];
NSLog(@"date1 = %@", date1.description);
date2 = [fmt dateFromString:@"2001-05-05 22:34:56"];
NSLog(@"date2 = %@", date2.description);
date3 = [fmt dateFromString:@"2001-05-05 12:34:56PM"];
NSLog(@"date3 = %@", date3.description);
date4 = [fmt dateFromString:@"2001-05-05 12:34:56 PM"];
NSLog(@"date4 = %@", date4.description);
[fmt release];
fmt = [[BNSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
dateString = [fmt stringFromDate:[NSDate date]];
NSLog(@"dateString = %@", dateString);
date1 = [fmt dateFromString:@"2001-05-05 12:34:56"];
NSLog(@"date1 = %@", date1.description);
date2 = [fmt dateFromString:@"2001-05-05 22:34:56"];
NSLog(@"date2 = %@", date2.description);
date3 = [fmt dateFromString:@"2001-05-05 12:34:56PM"];
NSLog(@"date3 = %@", date3.description);
date4 = [fmt dateFromString:@"2001-05-05 12:34:56 PM"];
NSLog(@"date4 = %@", date4.description);
[fmt release];
结果:
2011-07-11 17:44:43.243 DemoApp[160:307] Category's locale: <__NSCFLocale: 0x11a820> en_US_POSIX
2011-07-11 17:44:43.257 DemoApp[160:307] dateString = 2011-07-11 05:44:43 PM
2011-07-11 17:44:43.264 DemoApp[160:307] date1 = (null)
2011-07-11 17:44:43.272 DemoApp[160:307] date2 = (null)
2011-07-11 17:44:43.280 DemoApp[160:307] date3 = (null)
2011-07-11 17:44:43.298 DemoApp[160:307] date4 = 2001-05-05 05:34:56 PM +0000
2011-07-11 17:44:43.311 DemoApp[160:307] Extended class's locale: <__NSCFLocale: 0x11a820> en_US_POSIX
2011-07-11 17:44:43.336 DemoApp[160:307] dateString = 2011-07-11 17:44:43
2011-07-11 17:44:43.352 DemoApp[160:307] date1 = 2001-05-05 05:34:56 PM +0000
2011-07-11 17:44:43.369 DemoApp[160:307] date2 = 2001-05-06 03:34:56 AM +0000
2011-07-11 17:44:43.380 DemoApp[160:307] date3 = (null)
2011-07-11 17:44:43.392 DemoApp[160:307] date4 = (null)
手机[将iPod Touch设为]设置为英国,12 / 24开关设置为12.两个结果有明显区别,我判断类别版本是错误的。请注意,类别版本IS中的日志正在执行(并且代码中的停止位置被命中),因此不仅仅是代码的某种情况不会被使用。
The phone [make that an iPod Touch] is set to Great Britain, with the 12/24 switch set to 12. There's a clear difference in the two results, and I judge the category version to be wrong. Note that the log in the category version IS getting executed (and stops placed in the code are hit), so it's not simply a case of the code somehow not getting used.
由于我还没有收到任何适用的回复,我会将奖金截止日期延长一两天。
Since I haven't gotten any applicable replies yet I'll extend the bounty deadline for another day or two.
Bounty将在21小时内结束 - 即使答案在我的案例中并不真正有用,它也会转到那些尽最大努力帮助的人。
Bounty ends in 21 hours -- it'll go to whoever makes the most effort to help, even if the answer isn't really useful in my case.
稍微修改了类别实现:
#import "NSDateFormatter+Locale.h"
@implementation NSDateFormatter (Locale)
- (id)initWithSafeLocale {
static NSLocale* en_US_POSIX2 = nil;
self = [super init];
if (en_US_POSIX2 == nil) {
en_US_POSIX2 = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
NSLog(@"Category's locale: %@ %@", en_US_POSIX2.description, [en_US_POSIX2 localeIdentifier]);
[self setLocale:en_US_POSIX2];
NSLog(@"Category's object: %@ and object's locale: %@ %@", self.description, self.locale.description, [self.locale localeIdentifier]);
return self;
}
@end
基本上只是更改了名称静态语言环境变量(如果与子类中声明的静态存在某些冲突)并添加了额外的NSLog。但看看NSLog打印的是什么:
Basically just changed the name of the static locale variable (in case there was some conflict with the static declared in the subclass) and added the extra NSLog. But look what that NSLog prints:
2011-07-15 16:35:24.322 DemoApp[214:307] Category's locale: <__NSCFLocale: 0x160550> en_US_POSIX
2011-07-15 16:35:24.338 DemoApp[214:307] Category's object: <NSDateFormatter: 0x160d90> and object's locale: <__NSCFLocale: 0x12be70> en_GB
2011-07-15 16:35:24.345 DemoApp[214:307] dateString = 2011-07-15 04:35:24 PM
2011-07-15 16:35:24.370 DemoApp[214:307] date1 = (null)
2011-07-15 16:35:24.378 DemoApp[214:307] date2 = (null)
2011-07-15 16:35:24.390 DemoApp[214:307] date3 = (null)
2011-07-15 16:35:24.404 DemoApp[214:307] date4 = 2001-05-05 05:34:56 PM +0000
正如您所看到的,setLocale根本没有。格式化程序的语言环境仍为en_GB。似乎某个类别中的init方法存在奇怪。
As you can see, the setLocale simply didn't. The locale of the formatter is still en_GB. It appears that there is something "strange" about an init method in a category.
参见下面的。
推荐答案
Duh !!
有时你有一个啊哈!!那一刻,有时它更像是Duh !!这是后者。在 initWithSafeLocale
的类别中,super init
被编码为 self = [super init] ];
。这在 NSDateFormatter
的SUPERCLASS中,但不是 init
NSDateFormatter
对象本身。
Duh!!
Sometimes you have an "Aha!!" moment, sometimes it's more of a "Duh!!" This is the latter. In the category for initWithSafeLocale
the "super" init
was coded as self = [super init];
. This inits the SUPERCLASS of NSDateFormatter
but does not init
the NSDateFormatter
object itself.
显然,当跳过此初始化时, setLocale
反弹,大概是因为某些缺失对象中的数据结构。将 init
更改为 self = [self init];
会导致 NSDateFormatter
初始化发生, setLocale
再次开心。
Apparently when this initialization is skipped, setLocale
"bounces off", presumably because of some missing data structure in the object. Changing the init
to self = [self init];
causes the NSDateFormatter
initialization to occur, and setLocale
is happy again.
这是最终源代码category的.m:
Here is the "final" source for the category's .m:
#import "NSDateFormatter+Locale.h"
@implementation NSDateFormatter (Locale)
- (id)initWithSafeLocale {
static NSLocale* en_US_POSIX = nil;
self = [self init];
if (en_US_POSIX == nil) {
en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
[self setLocale:en_US_POSIX];
return self;
}
@end
这篇关于处理NSDateFormatter语言环境“feechur”的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!