处理 NSDateFormatter 语言环境“feechur"的最佳方法是什么? [英] What is the best way to deal with the NSDateFormatter locale "feechur"?

查看:26
本文介绍了处理 NSDateFormatter 语言环境“feechur"的最佳方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎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];

然后它在美国和大多数语言环境中都可以正常工作,直到……将手机设置为 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.

(参见,例如,NSDateFormatter,我做错了什么还是这是一个错误?)

(并参见 https://developer.apple.com/library/content/qa/qa1480/_index.html)

显然,Apple 已经宣布这是坏的"——按设计损坏,他们不会修复它.

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!

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)

手机[make that an iPod Touch]设置为英国,12/24开关设置为12.两个结果有明显差异,我判断类别版本错误.请注意,类别版本中的日志正在执行(并命中放置在代码中的停止点),因此这不仅仅是代码不知何故未被使用的情况.

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.

赏金将在 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!!"这是后者.在 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.

这是最终"类别的 .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"的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆