要約
- カスタムフォーマットの日時文字列からDate変換時にnilが返却される。
- シミュレータでは発生しない、実機で発生する
- 国内のみのサービスでもDateFormatterにはLocaleは必ず設定し利用する。
- 可能であれば実機利用のテストのタイミングに組み込む
現象
文字列からDate変換するときに、端末の設定が12時間表記になっていると必ずnilが発生。
シミュレータでは発生しないので、忘れがち。
問題になるパターン
変換文字列 | 24時間 | 12時間 | シミュレータ |
---|---|---|---|
時刻を含む文字列 | 成功 | 失敗(nil) | 成功 |
時刻を含まない文字列 | 成功 | 成功 | 成功 |
参考 問題になるコード
let dateFormmater = DateFormatter()
dateFormmater.dateFormat = "yyyy-MM-dd HH:mm:ss"
/// 12時間表記の際に date == nil となる.
let date = dateFormmater.date(from: "2020-03-02 10:00:00")
対処方法
Formatter設定時Localeを設定する
実機でもdateFormatterにはLocaleが設定されているものの、localeを改めて設定する必要がある。
let dateFormmater = DateFormatter()
dateFormmater.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormmater.locale = Locale(identifier: "en_US_POSIX")
/// 12時間表記の際でもnilとならない。
let date = dateFormmater.date(from: "2020-03-02 10:00:00")
忘れがちなのでExtenstionにしてしまう.
状況によって固定値も含めてしまうとよい。
public extension DateFormatter {
static var standard: DateFormatter {
let standard = DateFormatter()
standard.dateFormat = "yyyy-MM-dd HH:mm:ss"
standard.locale = Locale(identifier: "en_US_POSIX")
return standard
}
}
コードで強力に制約をするのであれば、DateFormatterをwrapするのが良さそう。
おまけ
海外対応時のメッセージの受信時刻表示で必要なこと
- 時刻データのタイムゾーンとクライアントのタイムゾーンを考慮する
- 時刻表記のフォーマットを考慮する(ここでは触れていない)
let dateFormmater = DateFormatter()
dateFormmater.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormmater.locale = Locale(identifier: "en_US_POSIX")
/// 時刻データのタイムゾーンでDateへ変換.
dateFormatter.timeZone = TimeZone(abbreviation: "JST")
let date = dateFormmater.date(from: "2020-03-02 10:00:00")
/// 端末のタイムゾーンで文字列に変換.
dateFormatter.timeZone = TimeZone.current
let dateString = dateFormatter.string(from: date!)