SwiftでUNIX時間を扱うの巻

UNIX時間とDate型の変換について

UNIX時間からDate型の文字列に変換する際にちょっと詰まったので備忘録としてメモしておきます。

今回必要になったタスクは、APIを叩いてUNIX時間のデータを取得してそれをDate型に変換するというものです。

{
    "num": 457,
    "start": 1572328800,
    "end": 1572458400,
    "stage": 3,
}

返ってくる値は以下のような感じですね。

このうち1572328800という値がUNIX時間で、UTC時刻における1970年1月1日午前0時0分0秒からの経過秒数を表しています。

ちなみに2019年10月29日06:00:00を表してるんよ。

対してDate型というのは 20191029060000のような、人間がみて直感的にわかりやすい表現です。

APIを叩いて取得したUNIX時間のタイムスタンプをDate型にして別のAPIを叩くのが目的なので、これをDate型に変換します。

ちなみにAPIが受け付けるのは2019102906(四桁の西暦、0埋め月、0埋め日、24時間制の0埋め時)なのでyyyyMMddHHと指定してあげればいいことになります。

これ、意外と覚えにくいんだよねえ。

Swiftで実装

日付を扱うにはDateFormatter()を使うととっても便利です。

let time: Double = 1572328800
let f = DateFormatter()
f.dateFormat = "yyyyMMddHH"
debugPrint(f.string(from: Date(timeIntervalSince1970: time)))

最終的にDate型に変換するのはDateFormatter().string()という関数なのですが、ここの入力してDate型にtimeIntervalSince1970というオプション?を使うとUNIX時間を引数としてとることができます。

つまり、上のコードはUNIX時間(タイムスタンプ)である変数timeをdateFormatで指定したDate型に変換するというものです。

気をつけなければいけないのが、timeIntervalSince1970の引数は倍精度(Double型)でないといけません。Int型だと何かと問題がありますもんね、わかります。

TimeZone問題

さて、最初は上のコードでいいじゃんと思っていたのですが、北米ユーザの方から「履歴と記録が取得できない」とのバグ報告をいただきました。

そんなバカな、と思っていたのですがシミュレータでTimeZone変更するのってめんどくさくてデバッグしてなかったんですよね。

右(北米)のユーザのShift IDがズレてる!!

ここはすべてのユーザが同じ値を返さなければいけないはずなのに、TimeZoneによって値が変わってしまうことが判明したのです。

ということで、調べた結果なんとか修正することができたのでメモしておきます!!

TimeZone考慮したコード

let time: Double = 1572328800
let f = DateFormatter()
f.dateFormat = "yyyyMMddHH"
f.timeZone = NSTimeZone(name: "GMT") as TimeZone?
debugPrint(f.string(from: Date(timeIntervalSince1970: time)))

Date型に変換するDateFormatter()に対してTimeZoneを指定してあげることで、プログラムを実行するユーザがどこにいても常に指定されたTimeZoneで値を返すようにすることができました。

今回の場合は標準時刻を使いたかったのでGMTを指定していますが、お好きな標準時刻を使ってもらって大丈夫です。

せっかくタイムゾーンの話をしたのでタイムゾーンの関連書籍を貼ろうとしたのですが全く見つからなかったので仕方なく時計の紹介をしておきます。

個人的にはオメガのシーマスターがお気に入りです(本当)

まとめ

Swiftって最初はとっつきにくくて面倒くさい感じだったんですが、慣れてくると面白いなあって感じるようになってきました。

ただ、自分がソースコードを複数持っているプロジェクトを書いたことがないので変数の定義があっちらこっちらでわけわからないことになっちゃっているのがもったいないです。

コードの書き方というよりは、管理の仕方とかを学びたいですね。