iOSアプリ開発の逆引き辞典

iPhone/iPadで使えるアプリ開発のTipsをまとめてみました

カレンダー設定を和暦にすると2011年が西暦3999年と解釈されてしまう問題に対応する

2011年11月13日の場合、例えば「20111113」みたいに「yyyyMMdd」の形式でplistに保存していました。日付の判定にミスすることが判ったので調査してみたら、下記のエントリを発見しました。

iPhoneのカレンダー設定を和暦にしていると、日付と曜日がずれる問題が起こる - odawaraの「はてな de メモ」> 一般->言語設定->カレンダーで西暦以外(和暦orタイ仏歴)を選択していると、NSDateFormatterでフォーマットする年が平成yyyy年とかになるらしい。 <<

つまりどういう事かというと、「2011/11/13」という文字列をNSDateに変換してみましょう

 // 元になるNSDateを作成する(文字列→NSDate変換)
NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:@"yyyy/MM/dd"];
NSDate* _dateFirst = [dateFormatter dateFromString:@"2011/11/13"];
NSLog(@"result: %@", _dateFirst);

// 出力:2011-11-12 15:00:00 +0000

デバッガーには2011と正しく表示されています*1が、この時の2011は「西暦」ではなく「平成」です。その証拠にNSDateから文字列に直すと西暦3999年と出力されてしまいます。

// 元になるNSDateを作成する(文字列→NSDate変換)
NSDateFormatter* formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateFormat:@"yyyyMMdd"];
[formatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"ja_JP"] autorelease]];
[formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"JST"]];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[formatter setCalendar:calendar];

NSString* strDate = [formatter stringFromDate:_dateFirst];
NSLog(@"result: %@", strDate);

// 出力:result: 39991113

最初のコードの時点で意図しない状態になってしまっているので、ローケル、タイムゾーン、カレンダーをそれぞれきちんと設定してやると平成表記になります。

// 元になるNSDateを作成する
NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:@"yyyy/MM/dd"];
// ロケールの設定
[dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"ja_JP"] autorelease]];
// タイムゾーンの設定
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"JST"]];
// カレンダーの設定
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[dateFormatter setCalendar:calendar];
NSDate* _dateFirst = [dateFormatter dateFromString:@"2011/11/13"];
NSLog(@"result: %@", _dateFirst);

// 出力:0023-11-12 15:00:00 +0000

しかし、この手の処理は全部拡張メソッドカテゴリを用意して統一的に使う様にしないと修正も大変だし、ちょっとやってられない。

*1:UTCなので指定した日本日付から-9時間されている