ものすごいトラップに引っかかったのでメモ代わりに。
iOSで日付や時間を取り扱う際はNSDate
クラスとNSDateFormatter
を使用します。日付から文字列にする際はこのように出力フォーマットを指定します。
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy/MM/dd HH:mm:ss";
NSDate *date = [NSDate date];
NSString *formatString = [dateFormatter stringFromDate:date];
逆に文字列から日付にする際はこんな感じです。
NSString *dateString = @"2014/07/23 12:00:00";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy/MM/dd HH:mm:ss";
NSDate *date = [dateFormatter dateFromString:dateString];
だいたいこんな感じで問題なく使っていると思います。
が。
実はこの変換がうまく行かない場合があります。
時間表示が午前/午後表記=24時間表示がオフの場合です。
時間表記の切り替えは設定 > 一般 > 日付と時刻から選択できます。
ステータスバーに表示されている時間を見ると分かりやすいと思います。
この設定をしたときに文字列から日付への変換がうまくいきません。dateFromString
からnil
が返ってきます。NSDictionary
に入れようとすると最悪な事態になりますね。落ちます。
問題となるパターンとしては、日付のフォーマットを@"yyyy/MM/dd HH:mm:ss"
のようにベタ打ちしているパターン、csvファイルなどに日付フォーマットを決めて書かれているものを読み込んでNSDate
に変換しようとするパターンなど、フォーマットを固定して使用している場合がこれにあたります。
しかも困ったことに**シミュレーターは24時間表示切り替えができません。**実機で検証した上で、24時間表示の切り替えがあることを考慮してテストを行わないといけませんね。
で、これをどうやって解決したら良いか?こちらのドキュメントを参照してみましょう。ここにはこんなことが書かれています。
On the other hand, if you're working with fixed-format dates, you should first set the locale of the date formatter to something appropriate for your fixed format. In most cases the best locale to choose is "en_US_POSIX", a locale that's specifically designed to yield US English results regardless of both user and system preferences.
Google翻訳してみます(翻訳原文ママ)。
あなたは固定形式の日付で作業している一方、は、まず固定フォーマットに適したものに日付フォーマッタのロケールを設定する必要があります。ほとんどの場合、選択するのが最善のロケールが「en_US_POSIX」は、具体的に関係なく、ユーザとシステム環境の両方の米国英語の結果をもたらすように設計されていますロケールです。
ということなので、固定フォーマットの文字列を日付に変換する際はen_US_POSIX
をNSDateFormatter
のロケールに指定しましょう。
NSString *dateString = @"2014/07/23 12:00:00";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy/MM/dd HH:mm:ss";
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
NSDate *date = [dateFormatter dateFromString:dateString];
これで文字列から日付への変換は問題なくできるようになります。