LoginSignup
2
1

More than 3 years have passed since last update.

Dateを扱うときは12時間表記設定を考慮しよう。

Posted at

要約

  • カスタムフォーマットの日時文字列から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!)
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1