iOSアプリ開発で日時を扱う時の注意点(暦と24時間表示の設定)

今回は、iOSアプリ開発で日時を扱う時の注意点を紹介する。
日付型である「NSDate」型を、文字列型である「NSString」に変換する際、「NSDateFormatter」クラスを使用することが一般的である。
ただ、NSDateFormatterの設定によっては意図しない変換が行われることがあるので注意が必要である。

現在日時を「yyyy/MM/dd HH:mm:ss」形式の文字列に変換する場合、最小限の実装は以下の様になる。

//現在時刻を取得する
NSDate *now = [NSDate date];
    
//フォーマッターをインスタンス化する
NSDateFormatter *df = [[NSDateFormatter alloc] init];
    
//変換フォーマットの設定
df.dateFormat  = @"yyyy/MM/dd HH:mm:ss";
    
//NSDate型からNSString型にフォーマットに従って変換する
NSString *strDate = [df stringFromDate:now];
    
//結果をログに出力する    
NSLog(@"文字列時刻:%@", strDate);


このロジックを動作させた場合、iOS端末の設定によって、結果に以下の様なバラつきが起こる。

No. 24時間表示 結果
1 西暦 ON 2015/03/21 11:08:31
2 和暦 ON 0027/03/21 11:09:03
3 西暦 OFF 2015/03/21 午前11:10:24

「暦」の設定は[設定]>[一般]>[言語と地域]>[カレンダ]で行い、「24時間表示の設定」は[設定]>[一般]>[日付と時刻]>[24時間表示]で行う。

No.2の「年」部分と、No.3の「時間」部分は、多くの実装者が望む結果とは異なっていると思われる。
実装者が望む結果は「No.2とNo.3の結果もNo.1と同じであること」と考えている。

よって、No.2とNo.3の結果がNo.1と同じになる、NSDateFormatterの設定を紹介する。
下記の様にNSDateFormatterの設定に3行追加する。

//現在時刻を取得する
NSDate *now = [NSDate date];

//フォーマッターをインスタンス化する
NSDateFormatter *df = [[NSDateFormatter alloc] init];

df.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];  //...(1)
df.locale   = [NSLocale systemLocale];       //...(2)
df.timeZone = [NSTimeZone systemTimeZone];   //...(2)

//変換フォーマットの設定
df.dateFormat  = @"yyyy/MM/dd HH:mm:ss";

//NSDate型からNSString型にフォーマットに従って変換する
NSString *strDate = [df stringFromDate:now];

//結果をログに出力する
NSLog(@"文字列時刻:%@", strDate);


<ソースコード解説>

番号 説明
(1) NSDateFormatterのcalendar属性に「NSGregorianCalendar」を設定することで、端末の暦の設定による結果のバラつきをなくす。
(2) NSDateFormatterのlocale属性・timeZone属性を明示的に設定することで、端末の24時間表示の設定による結果のバラつきをなくす。


<実行結果>

No. 24時間表示 結果
1 西暦 ON 2015/03/21 11:54:03
2 和暦 ON 2015/03/21 11:54:34
3 西暦 OFF 2015/03/21 11:54:53

取得形式にバラつきがなくなる事が確認できた。

Enjoy Programing!!

<お勧め書籍>

詳解 Objective-C 2.0 第3版
iOSアプリ開発技術者として仕事をするのであれば、必ず読んでおくべき書籍である。
筆者も何度も繰り返し精読している。