それはNSDateFormatter
予期せずあなたに噛み付く「機能」を持っているようです:あなたが次のような単純な「固定された」フォーマット操作を行う場合:
NSDateFormatter* fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyyMMddHHmmss"];
NSString* dateStr = [fmt stringFromDate:someDate];
[fmt release];
その後、米国およびほとんどのロケールで正常に動作します...電話が24時間地域に設定されているユーザーは、設定の12/24時間スイッチを12に設定します。結果の文字列の終わり。
(例えば、NSDateFormatterを参照してください、私は何か間違ったことをしていますか、これはバグですか?)
(そしてhttps://developer.apple.com/library/content/qa/qa1480/_index.htmlを参照してください)
どうやらAppleはこれを "悪い"と宣言している-Broken As Designedで、彼らはそれを修正するつもりはない。
回避策は明らかに、特定の地域、一般的には米国の日付フォーマッターのロケールを設定することですが、これは少し面倒です:
NSLocale *loc = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[df setLocale: loc];
[loc release];
onsies-twosiesではそれほど悪くありませんが、私は約10の異なるアプリを扱っています。最初に見たアプリには、このシナリオのインスタンスが43あります。
マクロ/オーバーライドされたクラス/コードを不明瞭にすることなく、すべてを変更する労力を最小限に抑えるための賢いアイデアはありますか?(私の最初の本能は、NSDateFormatterをinitメソッドでロケールを設定するバージョンでオーバーライドすることです。alloc/ init行と追加されたインポートの2行を変更する必要があります。)
追加されました
これは私がこれまでに思いついたものです-すべてのシナリオで機能するようです:
@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
バウンティ!
賞金は火曜日の正午までに私が目にする最高の(正当な)提案/批評に与えられます。[下記を参照-期限が延長されました。]
更新
OMZの提案について、これが私が見つけているものです-
カテゴリバージョンは次のとおりです-hファイル:
#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に設定されています。2つの結果には明らかな違いがあり、カテゴリバージョンは間違っていると判断します。カテゴリバージョンのログが実行される(そしてコードに配置されたストップがヒットする)ことに注意してください。そのため、コードが何らかの理由で使用されないだけではありません。
バウンティの更新:
該当する返信がまだないので、賞金の締め切りをもう1〜2日延長します。
バウンティは21時間で終了します。私の場合、答えが実際には役に立たない場合でも、支援に最も力を注ぐ人なら誰でも参加できます。
奇妙な観察
カテゴリーの実装を少し変更しました:
#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
基本的に、静的ロケール変数の名前を変更し(サブクラスで宣言されたstaticとの競合が発生した場合)、追加のNSLogを追加しました。しかし、NSLogが出力する内容を見てください。
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メソッドに「奇妙な」何かがあるようです。
最終回答
以下の承認された回答を参照してください。
- (NSDateFormatterBehavior)formatterBehavior
か?