

下記のコードを実行すると、現在時間とずれたデータが保存されます。ネットで調べたところグリニッジ天文台の時間が記録されるみたいです。日本時間が保存されるようにタイムゾーンを変更する方法を教えていただけますか。

環境はSwift ４、MacBookProです。

現在時間保存用のコード

[code]

    import UIKit
    import RealmSwift
    
    class inputViewController: UIViewController {
    
    @IBAction func save(_ sender: UIButton) {
         try! realm.write{
            self.diary.title = self.titleTextField.text!
            self.diary.body = self.bodyTextView.text
            self.diary.date = NSDate() // 問題の箇所
    
[/code]

現在時間表示用のコード

[code]

    import UIKit
    import RealmSwift
    
    class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    ...
    
    //セルの内容
        func tableView(_ tableView:UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //再利用可能なセル
            let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "Cell")
    //セルに値を設定する
            let object = dataArray[indexPath.row]
            cell.textLabel?.text = object.title
            cell.detailTextLabel?.text = object.date.description // 問題の箇所
    ...
    }
    
[/code]


CC BY-SA 3.0
2017-11-15T11:19:28.750
39598
2017-11-17T05:01:08.473
2017-11-17T04:39:28.843
5519
13657
question
swift
タイムゾーンの変更方法を教えていただけますか。


コメントに書いたようにAppleのFoundationフレームワークの`NSDate`やそのSwift版の`Date`にはタイムゾーンを持ちません。通常、データ型を`NSDate`や`Date`とした場合、表示の際にタイムゾーンを反映させるようにします。

`NSDate`を表示用の文字列に変換しているのはこの行だけのようですね。

[code]

        cell.detailTextLabel?.text = object.date.description
    
[/code]

残念ながら`description`プロパティでの文字列への変換は、現在のデバイスのタイムゾーン設定などを反映してくれません。(と言うか、きちんと動作が定義されていないので、バージョンによって全然違った表示になってしまう可能性すらあります。)

`NSDate`(または`Date`)型を表示用の文字列に変換する場合には`DateFormatter`を使用してください。

[code]

    class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
        //...
    
        //`DateFormatter`のインスタンスを作ってプロパティに保持しておく
        let dateFormatter: DateFormatter = {
            let df = DateFormatter()
            //デバイスの各種設定(タイムゾーン含む)に合わせ、システム標準の書式.mediumを使用する
            df.dateStyle = .medium
            df.timeStyle = .medium
            return df
        }()
    
        //...
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            //...
            //cell.detailTextLabel?.text = object.date.description の行を以下のように変更
            cell.detailTextLabel?.text = dateFormatter.string(from: object.date as Date)
            //...
        }
    
        //...
    }
    
[/code]

上記のコードでは、「日本時間」ではなく、デバイスに設定されている時間帯で時刻が表示されますが、デバイスの現在の設定によらず強制的に日本時間にする場合には、タイムゾーンを指定してください。

[code]

    let dateFormatter: DateFormatter = {
        let df = DateFormatter()
        //デバイスの言語・12/24時間表示の設定に合わせるが、タイムゾーンだけ強制的に日本にする
        df.timeZone = TimeZone(identifier: "Asia/Tokyo")
        //システム標準の書式のうち.mediumを使用する
        df.dateStyle = .medium
        df.timeStyle = .medium
        return df
    }()
    
[/code]

`dateStyle`,
`timeStyle`を用いるとApple製の内蔵アプリっぽい日時の表示になりますが、逆にそれが気に食わない場合に、カスタム書式を指定する場合にはこんなコードになります。

[code]

    let dateFormatter: DateFormatter = {
        let df = DateFormatter()
        //デバイスのタイムゾーンの設定に合わせ、書式だけ独自のスタイルにする
        df.dateFormat = "yyyy/MM/dd HH:mm:ss"
        df.locale = Locale(identifier: "en_US_POSIX")   //<-他のデバイス設定が書式に影響を与えないようにする
        return df
    }()
    
[/code]

タイムゾーンを強制的に指定したいのであれば、さっきと同じように`timeZone`プロパティを設定する1行を加えてください。

`DateFormattr`には他にも色々設定項目がありますが、「ios
dateformatter」あたりで検索すれば良記事が多数ヒットしますし、その中には(英語記事を禁止にしていなければ)[Appleの公式リファレンス](https://developer.apple.com/documentation/foundation/dateformatter)なんかも見つかると思いますので、所望の表示形式となるよう調べて見てください。

* * *

ちなみに上記の方法で「表示の際にデバイスタイムゾーンを指定する」と言う方法では、日時を保存した後ユーザが移動してデバイスのタイムゾーンを変更すると、表示される日時がユーザの意識しているものとは異なってしまうかもしれません。

このような動作がいやなら、`NSDate`や`Date`を使わずに、データ型を`String`に設定して、「保存の際に(タイムゾーンを考慮して)日付を表す文字列に変換し、その文字列を保存する」ようにした方が良いかもしれません。ただ、この際にも`DateFormatter`は使用することになるでしょう。


CC BY-SA 3.0
2017-11-17T05:01:08.473
39641
2017-11-17T05:01:08.473
2020-06-17T08:14:45.997
-1
13972
39598
answer