2012-03-31
iPhoneで和暦表示設定のとき、日付や曜日がずれる
GoogleCalendarの予定をiPhoneに表示するアプリを作成中、
実機で動かすと、2012年4月1日の曜日が1日ずれていることを発見。
4000年4月1日(土) ←2012年4月1日は日曜日…
ん?4000年??
年まで変わってる!
iPhoneの設定で、カレンダーの設定を和暦にしているとこうなる。
西暦に変更すればちゃんと「2012年4月1日(日)」と表示されるのだが。
よく分からないので、Googleで調べてみると、以下のページを発見。
カレンダー設定を和暦にすると2011年が西暦3999年と解釈されてしまう - 酢ろぐ
まさに同じ状態。文字列からNSDate型に変換するとき、逆にNSDate型から文字列に変換するときには「NSGregorianCalendar」を使う必要があるようだ。
他のブログには、NSJapaneseCalendarの記事もあった。
カレンダーにもいろいろと種類があるんだな。*1
文字列からNSDate型へ変換
文字列を切り取って、NSDateComponentsにセットし、
そこからNSDate型変数を作成する。
NSDateComponents *comps = [[NSDateComponents alloc] init]; NSDate *date; @try { [comps setYear: 2012]; // Year [comps setMonth: 4]; // Month [comps setDay: 1]; // Day [comps setHour: 15]; // Hour [comps setMinute: 0]; // Minute [comps setSecond: 0]; // Second } @catch (NSException *exception) { NSLog(@"error was cought at NSDateComponents set values"); } NSCalendar *calendar = [NSCalendar currentCalendar]; NSCalendar *gregorianCalendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar]; NSCalendar *japaneseCalendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSJapaneseCalendar]; date = [calendar dateFromComponents:comps]; // currentCalendarで実行 NSLog(@"calendar date[%@]", date); date = [gregorianCalendar dateFromComponents:comps]; // NSGregorianCalendarで実行 NSLog(@"gregorianCalendar date[%@]", date); date = [japaneseCalendar dateFromComponents:comps]; // NSJapaneseCalendarで実行 NSLog(@"japaneseCalendar date[%@]", date);
実行結果をまとめるとこんな感じ。
西暦設定 | 和暦設定 | |
currentCalendar | 2012-04-01 06:00:00 +0000 (西暦2012年) | 2012-04-01 06:00:00 +0000 (平成2012年) |
NSGregorianCalendar | 2012-04-01 06:00:00 +0000 (西暦2012年) | 0024-04-01 06:00:00 +0000 (平成24年) |
NSJapaneseCalendar | 4000-04-01 06:00:00 +0000 (西暦4000年) | 2012-04-01 06:00:00 +0000 (平成2012年) |
※()内は追記した
数字だけを見ていれば「currentCalendar」で問題なさそうだが、
システムの表示形式が変わっているため、「currentCalendar+和暦設定」では平成2012年になるのだ Σ(゚д゚lll)
ちなみによく見ると、時間が9時間ずれている。
Timezoneが「+0000」になっているため、合っているのだがわかりにくいな(´・ω・`)
NSJapaneseCalendarでは、NSDateを作るときに「2012年」を渡しているが、
これが「平成2012年」と解釈されるため、西暦にすると「西暦4000年」になっている。
つまり、NSJapaneseCalendarを使うときは、年は和暦にして作業しなければならないということ。
もろもろ考えると、日付は西暦のGMT(標準時)で作業することに統一して、
NSGregorianCalendarを使うことにしたほうがよさそう。
NSDate型から文字列を作成
今度は逆にNSDate型から日付文字列を作るときの話。
NSDateFormatter *format; NSString *str; NSDate *date = [NSDate date]; // 現在時間で作成 format = [[NSDateFormatter alloc]init]; [format setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"ja_JP"]]; [format setDateFormat:@"yyyy年MM月dd日(EE) HH時mm分ss秒"]; // 時間文字列のフォーマット定義 NSCalendar *calendar = [NSCalendar currentCalendar]; NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSCalendar *japaneseCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSJapaneseCalendar]; [format setCalendar:calendar]; // currentCalendarで実行 str = [format stringFromDate:date]; NSLog(@"currentCalendar date[%@]", str); [format setCalendar:gregorianCalendar]; // NSGregorianCalendarで実行 str = [format stringFromDate:date]; NSLog(@"NSGregorianCalendar date[%@]", str); [format setCalendar:japaneseCalendar]; // NSJapaneseCalendarで実行 str = [format stringFromDate:date]; NSLog(@"japaneseCalendar date[%@]", str);
実行結果はこんな感じ。
西暦設定 | 和暦設定 | |
currentCalendar | 2012年03月31日(土) 20時32分27秒 | 0024年03月31日(土) 20時33分58秒 |
NSGregorianCalendar | 2012年03月31日(土) 20時32分27秒 | 2012年03月31日(土) 20時33分58秒 |
NSJapaneseCalendar | 0024年03月31日(土) 20時32分27秒 | 0024年03月31日(土) 20時33分58秒 |
西暦表示したいときは「NSGregorianCalendar」を使い、
和暦表示したいときは「NSJapaneseCalendar」を使えばいいようだ。
「currentCalendar」はカレンダーの設定が西暦の時には「NSGregorianCalendar」
和暦の時には「NSJapaneseCalendar」を使っているような動きをしているけど、
アプリが西暦のつもりでユーザが和暦設定にすると、変な値(西暦4000年など)になるから使わない方がいい。
欧米なんかはカレンダーの設定を変えようがないだろうから、currentCalendarでも問題は起きないだろうけど、
日本や中国など、独自の暦を使っている環境だと、ユーザ設定によってこんな問題が起きるんだなと。
LocaleやTimezoneは付属的なものだからいいとしても、
日付処理はなかなかやっかいだな。
*1:詳しく知りたいときは「NSLocale.h」を参照
- 2 http://ezsch.ezweb.ne.jp/search/?query=西暦4000年カレンダー&ct=0001&pd=1&sr=0000
- 2 http://www.google.co.jp/url?sa=t&rct=j&q=[[nscalendar alloc] initwithcalendaridentifier:nsgregoriancalendar]&source=web&cd=2&ved=0CCoQFjAB&url=http://d.hatena.ne.jp/yuriken27/20120331/1333196649&ei=2tt7T-3_PIeImQWnz8jgCw&usg=AFQj
- 2 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&frm=1&source=web&cd=1&ved=0CDQQFjAA&url=http://d.hatena.ne.jp/yuriken27/20120331/1333196649&ei=vV1-T7byC6fGmAWTiPz8DQ&usg=AFQjCNFcXbF0a4NJUfRpOkLUPgOs-0YyjQ
- 2 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&sqi=2&ved=0CDEQFjAA&url=http://d.hatena.ne.jp/yuriken27/20120331/1333196649&ei=iZl7T7G3EoyamQWSvfi4Aw&usg=AFQjCNFcXbF0a4NJUfRpOkLUPgOs-0YyjQ&sig2=53BiKC9QlwbN6_I9cEdDzw
- 2 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0CDAQFjAB&url=http://d.hatena.ne.jp/yuriken27/20120331/1333196649&ei=wH94T-3nFITFmQXh2tzpDw&usg=AFQjCNFcXbF0a4NJUfRpOkLUPgOs-0YyjQ&sig2=7NeFKlfWbRPCUTycp_Zhkw
- 2 http://www.google.co.jp/url?sa=t&rct=j&q=iphone 日付 4日&source=web&cd=3&ved=0CD8QFjAC&url=http://d.hatena.ne.jp/yuriken27/20120331/1333196649&ei=Urp8T-P8G6-5iAeixIGUCQ&usg=AFQjCNFcXbF0a4NJUfRpOkLUPgOs-0YyjQ
- 1 http://d.hatena.ne.jp/ch3cooh393/
- 1 http://search.yahoo.co.jp/search?p=平成24年 3月31日 西暦&search.x=1&fr=top_ga1_sa&tid=top_ga1_sa&ei=UTF-8&aq=&oq=
- 1 http://search.yahoo.co.jp/search?p=NSCalendar+日付がずれる&aq=-1&oq=&ei=UTF-8&fr=top_ga1_sa&x=wrt
- 1 http://www.google.co.jp/hws/search?hl=ja&client=fenrir&channel=&adsafe=off&safe=off&q=wget+GMT+9??????+??????&lr=all