Help us understand the problem. What is going on with this article?

Firestore の Timestamp の仕様変更による警告と、その対処

2019年6月21日追記

firebase@5.8.0 以降では firestore.Timestamp クラスがデフォルトになり、ここで説明したオプションは非推奨になった

The timestampsInSnapshots setting now defaults to true and you no
longer need to explicitly set it. In a future release, the setting
will be removed entirely and so it is recommended that you remove it
from your firestore.settings() call now.

CHANGELOG によれば、 firestore@1.0.0 で切り替わっている
https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore/CHANGELOG.md#100

firestore@1.0.0 は、 firebase のバージョンでいうと、 firebase@5.8.0 のリリースに含まれる(らしい)
https://firebase.google.com/support/release-notes/js#version_580_-_jan_17_2019

firestore.Timestamp クラスが追加された

Firebase@4.13.0 から firestore.Timestamp クラスが追加された
オプションで有効化することで, Timestamp 型のフィールドは新しい Timestamp クラスのインスタンスとして取得できる(今までは Date 型で取得できた)
このオプションはのちにデフォルトで有効化されるそうなので, 対応する必要がある

[feature] Added a new Timestamp class to represent timestamp fields, currently supporting up to microsecond precision. It can be passed to API methods anywhere a JS Date object is currently accepted. To make DocumentSnapshots read timestamp fields back as Timestamps instead of Dates, you can set the newly added flag timestampsInSnapshots in FirestoreSettings to true. Note that the current behavior (DocumentSnapshots returning JS Date objects) will be removed in a future release. Timestamp supports higher precision than JS Date.

https://github.com/firebase/firebase-js-sdk/blob/firebase%404.13.0/packages/firestore/CHANGELOG.md

  • CHANGELOG には Unreleased と書かれているので分かりづらいが, この時点で npm install した firebase には新しい Timestamp の仕様が含まれている
  • このあと Firestore@0.4.0 で正式?に CHANGELOG に載ることになる

https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore/CHANGELOG.md#040

警告

今までと同じように Firestore に Date 型のデータを入れると次のような警告がコンソールに表示される

[Date 型の値]  @firebase/firestore: Firestore (4.13.0):
The behavior for Date objects stored in Firestore is going to change
AND YOUR APP MAY BREAK.
To hide this warning and ensure your app does not break, you need to add the
following code to your app before calling any other Cloud Firestore methods:

  const firestore = firebase.firestore();
  const settings = {/* your settings... */ timestampsInSnapshots: true};
  firestore.settings(settings);

With this change, timestamps stored in Cloud Firestore will be read back as
Firebase Timestamp objects instead of as system Date objects. So you will also
need to update code expecting a Date to instead expect a Timestamp. For example:

  // Old:
  const date = snapshot.get('created_at');
  // New:
  const timestamp = snapshot.get('created_at');
  const date = timestamp.toDate();

Please audit all existing usages of Date when you enable the new behavior. In a
future release, the behavior will change to the new behavior, so if you do not
follow these steps, YOUR APP MAY BREAK.

対処

指示通りこんな風に変更する

import firebase from 'firebase';
import 'firebase/firestore';

const config = {
    /* firebase config */
};
firebase.initializeApp(config);

const firestore = firebase.firestore();
const settings = { timestampsInSnapshots: true };
firestore.settings(settings);

あたらしい Timestamp クラスは Date のメソッドを持っている訳ではないので, 勝手に変更されるとアプリケーションが壊れてしまう. そこで, 明示的に Timestamp クラスに変換させるオプションが追加されている

次に Timestamp 型を扱っている箇所を すべて 次のように修正する

const timestamp = snapshot.get('created_at');

const date = timestamp.toDate(); // JS Date 型が欲しい場合
const seconds = timestamp.seconds; // 秒数が欲しい場合
const nanoseconds = timestamp.nanoseconds; // ナノ秒(?)が欲しい場合 (主にサーバ側で作ったタイムスタンプ用)

所感

サーバ側のタイムスタンプはマイクロ秒単位で保存されているらしい. しかし JS Date 型はミリ秒単位でしか値を保持できないので, 変換時に切り詰めが発生する. これでは不便だし, バグの原因にもなるかも知れない. だから JS Date を標準で使うのはやめて, みんなが使える Timestamp クラスを用意しよう, ということだと理解している

TypeScript を使っているケースでは嬉しいアップデートなんじゃないかと思う. 残念ながら flow-typed には未だ反映されていない. 頑張ろう

参照

https://firebase.google.com/docs/reference/js/firebase.firestore.Timestamp

https://github.com/firebase/firebase-js-sdk/pull/544

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした