【Swift】TimeZone初期化時の注意点 【サマータイム】


# TimeZoneの初期化

日本時間はグリニッジ標準時となるGMTより +9時間 した時間となります。
swiftのDate型はGMT基準となるため、DateFormatter等で文字列に変換する場合
TimeZoneを日本時間に指定する必要があります。

TimeZoneの初期化には、identifierの指定と、GMTからの時間差で指定する方法があり、
どちらにしても結果的に時間を +9時間調整するので、好きな方を使って構いません。


```swift:identifier
TimeZone(identifier: "Asia/Tokyo")
```

```swift:GMT
TimeZone(secondsFromGMT: 9 * 60 * 60) // 9時間分の秒数
```

**TimeZone - Foundation | Apple Developer Documentation**
https://developer.apple.com/documentation/foundation/timezone


# TimeZoneの動作検証

と思ってたんですが、
実は、それぞれの指定で時間の表現に差が出てしまうのです。。。

試しに、UIDatePickerで設定した時間をラベルに表示しながら確認してみましょう。。

## 1970 年 1 月 1 日

では、まず UNIX時間の下限値である 1970年から。
`1970/1/1 00:00:00`
![1970.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142886/6cb125b8-49b4-8e15-85a5-bbddf98293f4.png)
上部のラベルは、DatePickerで選択した日付をDateFormatterでStringに変換して
表示しています。

また、DatePickerのTimeZoneは`identifier: "Asia/Tokyo"`で指定しており、
DateFormatterは`secondsFromGMT: 9 * 60 * 60`で指定しています。

どちらも+9時間調整なので、表記は当然`1970/1/1 00:00:00`となっています。

## 1955 年 2 月 24 日

更に時をさかのぼり、iPhoneを作ったスティーブジョブスの誕生日にしてみましょう。
`1955/2/24 00:00:00`
![1955.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142886/028cf760-3a7e-4063-7c2b-1f873861d342.png)
こちらも、問題なく`1955/2/24 00:00:00`となっています。

## 1951 年 9 月 8 日

次はApple本社付近のサンフランシスコにあやかり、
サンフランシスコ講和条約が締結された日にさかのぼってみます。
`1951/9/8 00:00:00`
![1951.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142886/d12f262a-dac6-81ea-5ff2-e65b81c815a3.png)

**！！？？**
なんということでしょう！！
ラベルへの変換が`1951/9/7 23:00:00`となってしましました・・・

どちらも日本時間なのはずなのに。。

# 日本におけるサマータイム
というわけで、`identifier`での指定と`secondsFromGMT`の指定で
1時間の差異がでてしまいました。

実は 1950年あたりで日本ではサマータイムが採用されていたため、
この差が生まれるようです。

*70年前の日本で実施されていた「サマータイム」が3年で廃止された理由*
https://www.buzzfeed.com/jp/kotahatachi/summer-time-1948

具体的に説明すると、identifierでの指定の場合、日本という地域での指定になります。
一方、GMTでの指定の場合、標準時との時間差での指定になるので、日本という情報がありません。
そのため、サマータイム調整が発生しないようです。

## サマータイムの期間

サマータイムの具体的な期間については、国立天文台のwikiにまとめてありました。

| 年 | 期間 |
|:--|:--|
| 昭和23年 (1948) | 5/1 12:00 ～ 9/12 0:00 |
| 昭和24年 (1949) | 4/2 12:00 ～ 9/11 0:00 |
| 昭和25年 (1950) | 5/6 12:00 ～ 9/10 0:00 |
| 昭和26年 (1951) | 5/5 12:00 ～ 9/9 0:00 |

*暦Wiki/時刻/夏時刻 - 国立天文台暦計算室*
https://eco.mtk.nao.ac.jp/koyomi/wiki/BBFEB9EF2FB2C6BBFEB9EF.html

`identifier: "Asia/Tokyo"`でこの期間を利用した場合、
サマータイムと認識され、1時間マイナスされてしまいます。。
(サマータイム期間なので1時間足されているはずという前提で 結果1時間引いた値になる)

以前、2020年の東京オリンピックに向けてサマータイムを導入しようと言う議論がありましたが、
実はすでに日本で採用された実績があり、結果的に辞めて欲しい意見が多く4年で終了していたんですね。。

なぜこれをまた採用しようと思ったのか・・・

と、それはどうでもよく、日本にはサマータイムがあったため、
TimeZoneの指定には気をつけましょうという話でした。

特別な理由がなければ、TimeZoneの初期化時は`GMT`で統一しておいた方が
変な問題に悩まされなくて良いかもですね。

# 今回実験したViewControllerのコード

```swift:ViewController.swift

import UIKit

class ViewController: UIViewController {

    let adjustSecondsForJapan : TimeInterval = 9 * 60 * 60
    
    @IBOutlet weak var datePicker: UIDatePicker!
    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupDatePicker()
    }

    private func setupDatePicker() {
        datePicker.datePickerMode = .date
        datePicker.timeZone = TimeZone(identifier: "Asia/Tokyo")
        datePicker.date = Date(timeIntervalSince1970: -adjustSecondsForJapan)
        datePicker.locale = Locale(identifier: "ja-JP")
    }
    
    private func getDateStrings(from date: Date) -> String {
        let formatter = DateFormatter()
        formatter.timeZone = TimeZone(secondsFromGMT: Int(adjustSecondsForJapan))
        formatter.dateFormat = "yyyy/MM/dd HH:mm:ss"
        return formatter.string(from: date)

    }
    
    @IBAction func didChangeDatePicker(_ sender: UIDatePicker) {

        label.text = getDateStrings(from: sender.date)

    }
}

```

## github

*becky3/timezone_summertime_test: 日本におけるサマータイムの影響について確認するプロジェクト*
https://github.com/becky3/timezone_summertime_test