能登 要

札幌在住のiOSアプリ開発者。SwiftUI により分割されたデバイス間を縦横にやりとりできる考え方に転換しています。

iOSアプリ開発者。2009年のiPhoneアプリ開発開始時期から活動。開発言語のアップデートの中でSwiftUIおよび周辺技術に着目中。

Firebase のタイムスタンプ2種とiOS SDKのタイムスタンプ

端的にいうと

FirebaseデータストアサービスのタイプスタンプとiOS SDKのTimeinterval は桁調整が必要。

1) Firebaseが提供するデータストアサービス

GoogleのFirebase はRealtimeDatabase(旧Firebase)、とGoogleFirestoreの2つのデータストアサービスを提供している。登場タイミングは違えどモバイルおよびWebフロントエンドを意識したデータストアサービスとなっている。

データストアに格納する情報はRealtimeDatabase、GoogleFirestore 共にキーバリュー(KeyValue)で格納格納する。Valueに格納できる情報は基本的な型の他、本Blogの主題であるタイムスタンプを格納するための型が用意されている。

2) タイムスタンプ(timestamp)とは

コンピューター(スマートフォン含む)上でのタイムスタンプはコンピューターに都合が良い形式で保存された日付情報となる。タイムスタンプは特に言及がない場合、1970年1月1日00:00:00 UTCからの経過秒数で指定する。

なぜ1970年1月1日なのかについてはコンピューター黎明期に決めたものがそのまま使われている歴史的経緯があるもの、であるが本Blogではコンピューター上で日付を都合が良い取り決めとして1970年1月1日になってそのまま使われている程度に止める。

重要なのはコンピューターに都合が良い形式として数値が採用されている点。何が良いかというとタイムスタンプ同士の比較ができる点で、大小比較すればタイムスタンプのどちらが古いか/新しいかを判断できる。

タイムスタンプと比べて扱いが多少難しいのは日付指定で、日付が記録された地域(Timezone)や、サマータイムの有無によって実際の時間は異なるためそれらを考慮して使用する必要がある。iOS SDKを使い場合は、NSCalender、NSTimeZone、NSDateFormatter、NSLocaleなどユーティリティが用意されている。

3) Firebaseでのタイムスタンプ型の相違

RealtimeDatabase、GoogleFirestore でタイムスタンプ型の定義が異なる。Google内のサービスなのにタイムスタンプの型が異なるのは、Googleがかつてベンチャー企業だったFirebaseを買収した経緯があるためで、Google買収前にFirebaseが発表したRealtimeDatabaseの仕様をGoogleが引き継いだためである。

実際のタイムスタンプ型は以下のようになっている。

Header Header
RealtimeDatabase 浮動小数点 整数域でミリ秒指定、少数域でマイクロ秒指定
GoogleFireStore 構造体(TimeStamp型) 構造体内の定義seconds、nanosecondsでそれぞれ秒、ナノ秒指定

GoogleFireStoreのタイムスタンプはGoogle内の標準的な仕様に沿っているのに対して、RealtimeDatabaseのタイムスタンプは、整数でミリ秒、少数以下でマイクロ秒を指定するGoogleの標準的な仕様以前の指定方法となっている。

Timestamp2

Timestamp3

4) iOS アプリ上でのタイムスタンプ

iOS SDKにもタイムスタンプとして利用できるとして型Timeintervalとして用意されている。比較用に使用するタイムスタンプはDateオブジェクトから生成できる。

let now = Date()
let timeinterval = now.timeIntervalSince1970()

iOS SDKのTimeinterval型は浮動小数点型で、整数域で秒、少数域でミリ秒を示している。

Timestamp1

仕様が異なるためiOS アプリ上で、iOS SDKのタイムスタンプとRealtimeDatabase、GoogleFirestoreのタイムスタンプを比較する際、RealtimeDatabase、GoogleFireStoreそれぞれで変換が必要となってくる。

RealtimeDatabaseの場合

RealtimeDatabaseタイムスタンプ型 / 1000.0 = iOS SDKのTimestamp型

GoogleFireStoreの場合

\[GoogleFireStoreのTimeStamp型\].seconds + \[GoogleFireStoreのTimeStamp型\].nanoseconds / 1000000 = iOS SDKのTimestamp型

GoogleFireStoreの場合は、Firebase iOS SDK側でタイムスタンプの相互変換をサポートするユーティリティ機能が充実しているのでそちらを使用することをお勧めする。RealtimeDatabaseの場合はRealtimeDatabaseタイムスタンプ型が整数域がミリセカンドである点のみ注意すれば良い。

参考