2012年6月22日金曜日

NSDateFormatter - 文字列と日付の変換

よく忘れるのでこちらもメモ…。

フォーマットの指定

文字列 intputDateStr を inputDateFormatter で指定したフォーマットでパースしてNSDate に格納。それを outputDateFormatter で指定したフォーマットで文字列として出力するサンプル。
 NSDateFormatter *inputDateFormatter = [[NSDateFormatter alloc] init];
 [inputDateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss"];
 NSString *intputDateStr = @"2000/01/02 03:04:05";
 NSDate *inputDate = [inputDateFormatter dateFromString:intputDateStr];
 
 NSDateFormatter *outputDateFormatter = [[NSDateFormatter alloc] init];
 NSString *outputDateFormatterStr = @"yyyy/MM/dd HH:mm:ss";
 [outputDateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"JST"]];
 [outputDateFormatter setDateFormat:outputDateFormatterStr];
 NSString *outputDateStr = [outputDateFormatter stringFromDate:inputDate];
 NSLog(@"[in]%@ -> [out]%@(%@)", intputDateStr, outputDateStr, outputDateFormatterStr);
 [inputDateFormatter release];
 [outputDateFormatter release];
outputDateFormatterStrの文字列を変更(出力フォーマットを指定)する事により以下の様な出力が可能。
フォーマットの指定入力出力説明
yyyy/MM/dd HH:mm:ss2000/01/02 03:04:052000/01/02 03:04:05全てをゼロ埋め有りで出力。
yyyy/M/d H:m:s2000/01/02 03:04:052000/1/2 3:4:5月・日・時・分・秒のゼロ埋め無し。
yyyy/M/d H:m:s2000/11/22 13:44:552000/11/22 13:44:55もちろん、2桁のデータが入力された場合は2桁の出力に成ります。

タイムゾーン

フォーマットの指定入力出力説明
yyyy/M/d H:m:s z2000/01/02 03:04:052000/1/2 3:4:5 JSTzでタイムゾーンの出力が出来ます。
z zz zzz zzzz2000/01/02 03:04:05JST JST JST 日本標準時zが1~3つのときは英語の大文字の省略されたもの(日本だと3文字ですが国により常に4文字の場合も有ります)。zが4つの場合は詳細な説明文となります。
Z ZZ ZZZ ZZZZ2000/01/02 03:04:05+0900 +0900 +0900 GMT+09:00Zが1~3つのときは世界標準時からの差(日本の場合は+9時間)。Zが4つの場合は GMT に時差を加えたものになります。
JSTなどの省略された文字列については以下を参照下さい。
標準時 - Wikipedia
タイムゾーンを JST から PST に変更すると以下の様に成ります。
フォーマットの指定入力出力
yyyy/M/d H:m:s z2000/01/02 03:04:052000/1/1 10:4:5 GMT-08:00
z zz zzz zzzz2000/01/02 03:04:05GMT-08:00 GMT-08:00 GMT-08:00 アメリカ太平洋標準時
Z ZZ ZZZ ZZZZ2000/01/02 03:04:05-0800 -0800 -0800 GMT-08:00

Locale(地域指定)をUSにする

Localeの設定次第でも結果が異なります。
例えばLocaleをUSにしたい場合。プログラムは以下の様に記述します。
 NSDateFormatter *inputDateFormatter = [[NSDateFormatter alloc] init];
 [inputDateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss"];
 NSString *intputDateStr = @"2000/01/02 03:04:05";
 NSDate *inputDate = [inputDateFormatter dateFromString:intputDateStr];
 
 NSDateFormatter *outputDateFormatter = [[NSDateFormatter alloc] init];
 NSString *outputDateFormatterStr = @"z zz zzz zzzz";
 [outputDateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"] autorelease]];
 [outputDateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"PST"]];
 [outputDateFormatter setDateFormat:outputDateFormatterStr];
 NSString *outputDateStr = [outputDateFormatter stringFromDate:inputDate];
 NSLog(@"|%@|%@ -> %@||", outputDateFormatterStr, intputDateStr, outputDateStr);
 [inputDateFormatter release];
 [outputDateFormatter release];
localeの設定は以下の部分で行っています。
 [outputDateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"] autorelease]];
zzzz のときの文字列がアメリカ向けのもになっている事が確認できます。ちなみに日本に設定する場合は ja_JP となります。
フォーマットの指定入力出力
z zz zzz zzzz2000/01/02 03:04:05PST PST PST Pacific Standard Time
iPhoneの現在の設定に合わせる場合は以下の様に記述します。
iPhoneの設定を変える場合は「設定」アプリの「一般」-「言語環境」-「言語」。
 [outputDateFormatter setLocale:[NSLocale currentLocale]];

タイムゾーン

例えば以下の様なプログラムを書いた場合、LocaleはデフォルトではiPhoneに設定されているタイムゾーンが使用されます。
 NSDateFormatter *inputDateFormatter = [[NSDateFormatter alloc] init];
 NSString *inputDateStr = @"yyyy/MM/dd HH:mm:ss";
 [inputDateFormatter setDateFormat:inputDateStr];
 NSString *intputDateStr = @"2000/01/02 03:04:05";
 NSDate *inputDate = [inputDateFormatter dateFromString:intputDateStr];
 NSLog(@"%@ -> %@", inputDateStr, [inputDate description]);
 [inputDateFormatter release];
そのため日本の設定でこのプログラムを実行すると明示的な記述が無いタイムゾーンについては自動的に日本のタイムゾーンで有る、+9時間に設定されます。
iPhoneの設定を変える場合は「設定」アプリの「一般」-「日時と時刻」-「時間帯」。
2000/01/02 03:04:05 -> 2000-01-02 03:04:05 +0900
iPhoneの設定を「太平洋標準時(米国、パシフィカ/Pacifica, USA)」に変更した後にプログラムを実行すると以下の様に出力されます。
2000/01/02 03:04:05 -> 2000-01-02 03:04:05 -0800
太平洋標準時の-8時間が設定されているのが確認できます。
次にタイムゾーンを日本(日本、東京/Tokyo, Japan)に設定し、以下のプログラムを実行します。
 NSDateFormatter *inputDateFormatter = [[NSDateFormatter alloc] init];
 NSString *inputDateStr = @"yyyy/MM/dd HH:mm:ss Z";
 [inputDateFormatter setDateFormat:inputDateStr];
 NSString *intputDateStr = @"2000/01/02 03:04:05 +0800";
 NSDate *inputDate = [inputDateFormatter dateFromString:intputDateStr];
 NSLog(@"%@ -> %@", inputDateStr, [inputDate description]);
 [inputDateFormatter release];
この場合、以下の様になります。
yyyy/MM/dd HH:mm:ss Z -> 2000-01-02 04:04:05 +0900
入力の文字列に指定した時分秒は 03:04:05 ですがタイムゾーンが日本の+9時間より1時間過去である+8時間のタイムゾーンでの日時であるため+9時間のタイムゾーンへの変更が行われた結果、 04:04:05 と1時間進んだ時間に変更されています。
また、Localeの話のところで確認した様にLocaleの設定によりタイムゾーンの記述方法が異なります。
フォーマットの指定Loacleの設定入力出力
z zz zzz zzzz日本2000/01/02 03:04:05GMT-08:00 GMT-08:00 GMT-08:00 アメリカ太平洋標準時
z zz zzz zzzzアメリカ(太平洋標準時)2000/01/02 03:04:05PST PST PST Pacific Standard Time
そのためタイムゾーンを「アメリカ太平洋標準時」と指定する以下の様なプログラムを記述するとLocaleが米国の場合にパースが失敗し、結果が null(nil) と成ります。
 NSDateFormatter *inputDateFormatter = [[NSDateFormatter alloc] init];
 NSString *inputDateStr = @"yyyy/MM/dd HH:mm:ss zzzz";
 [inputDateFormatter setDateFormat:inputDateStr];
 NSString *intputDateStr = @"2000/01/02 03:04:05 Pacific Standard Time";
 NSDate *inputDate;
 
 // Localeが日本
 [inputDateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"ja_JP"] autorelease]];
 inputDate = [inputDateFormatter dateFromString:intputDateStr];
 NSLog(@"[日本]%@ -> %@", inputDateStr, [inputDate description]);

 // Localeが米国
 [inputDateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"] autorelease]];
 inputDate = [inputDateFormatter dateFromString:intputDateStr];
 NSLog(@"[米国]%@ -> %@", inputDateStr, [inputDate description]);

 [inputDateFormatter release];
出力結果は以下。
[日本]yyyy/MM/dd HH:mm:ss zzzz -> 2000-01-02 20:04:05 +0900
[米国]yyyy/MM/dd HH:mm:ss zzzz -> (null)
逆に「Pacific Standard Time」と指定するとLocaleが日本の時にパースに失敗します。
[日本]yyyy/MM/dd HH:mm:ss zzzz -> (null)
[米国]yyyy/MM/dd HH:mm:ss zzzz -> 2000-01-02 20:04:05 +0900
この様にLocaleにより、パースに影響が有りますので適切なLocaleを指定した上で dateFromString: を実行しましょう。

24時間設定をOFFの環境での注意点

iPhoneでは時間の表示をユーザが24時間表示と午前/午後の2つのパターンを選択できます。
※「設定」「一般」「日付と時刻」に有る「24時間表示」で設定可能。
この「24時間表示」ですが、OFFのときにLocaleを設定していないとNSDateFormatterでHHを指定しても12時間表示での値が返ってくるようです。
Localeを指定した場合はHHでちゃんと24時間表示で返される様なのでLocaleは常に設定する様にしておきましょう。
詳しくはこちらのサイトに良くまとまっています。
日本語環境では、NSDateFormatterでフォーマットした日付がおかしい - 24/7 twenty-four seven

関連サイト

これで主な用途には問題ないとは思いますがその他のフォーマットについても知っておきたい人は以下のページなどを参照下さい。
UTS #35: Locale Data Markup Language
NSDateFormatter
言語設定も意外と曲者なので以前、こちらのエントリーで解説しました。

0 件のコメント:

コメントを投稿