今更ながら Firebase を使う機会が増えてきて Cloud Firestore のタイムスタンプ周りで何度か同じようなことを調べてしまっているのでメモ。
Cloud Firestore のタイムスタンプ型は Date
ではなく firebase.firestore.Timestamp
↑これ。
Cloud Firestore にタイムスタンプ型のデータを保存する方法
🙅 input type="date"
や input type="datetime-local"
の値をそのまま送ってもダメ。
import firebase from 'firebase/app'; import 'firebase/firestore'; const firebaseApp = firebase.initializeApp(FIREBASE_CONFIG); const db = firebaseApp.firestore(); // ... const [datetime, setDatetime] = useState(''); const postDataToFirebase = async () => { const addedDocRef = await db.collection(COLLECTION_NAME).add({ datetime: datetime, }); return addedDocRef; }; return ( <input type="datetime-local" value="datetime" onChange={(evt) => setDatetime(evt.currentTarget.value)} /> );
=> String 型のまま Cloud Firestore に登録 されてしまう
🙆 Timestamp
型に変換して送る
firebase.firestore.Timestamp.fromDate
メソッドで Timestamp
型に変換できる
import firebase from 'firebase/app'; import 'firebase/firestore'; const firebaseApp = firebase.initializeApp(FIREBASE_CONFIG); const db = firebaseApp.firestore(); // ... // Firestore の Timestamp に変換して返す const timestamp = (datetimeStr) => { return firebase.firestore.Timestamp.fromDate(new Date(datetimeStr)); }; const [datetime, setDatetime] = useState(''); const postDataToFirebase = async () => { const addedDocRef = await db.collection(COLLECTION_NAME).add({ datetime: timestamp(datetime), }); return addedDocRef; }; return ( <input type="datetime-local" value="datetime" onChange={(evt) => setDatetime(evt.currentTarget.value)} /> );
₍ ᐢ. ̫ .ᐢ ₎👌
cf. #データ型 Cloud Firestore にデータを追加する | Firebase
Date オブジェクトをそのまま送信しても大丈夫だった
Date オブジェクトをそのまま送信すると Firebase 側でよしなに Timestamp 型に変換してくれるみたいです
const postDataToFirebase = async () => { const addedDocRef = await db.collection(COLLECTION_NAME).add({ - datetime: timestamp(datetime), + datetime: new Date(datetime), }); return addedDocRef; };
サーバーで処理した時間のタイムスタンプを使う (created_at
, updated_at
)
firebase.firestore.FieldValue.serverTimestamp()
を使えばOK
// ... 略
const postDataToFirebase = async () => {
const addedDocRef = await db.collection(COLLECTION_NAME).add({
datetime: timestamp(datetime),
+ createdAt: firebase.firestore.FieldValue.serverTimestamp(),
});
return addedDocRef;
};
cf. #サーバーのタイムスタンプ Cloud Firestore にデータを追加する | Firebase
Cloud Firestore から取得した Timestamp を日付表示する
Cloud Firestore から取得した DocumentData にある Timestamp は seconds
というプロパティを持っているが、これを new Date()
に渡しても日付がズレてしまう。
new Date(seconds)
だと別の日付になってしまう問題
Cloud Firestore 上のデータ
createdAt: 2021年4月16日 16:18:17 UTC+9 dueDate: 2021年4月18日 16:18:00 UTC+9 isDone: false todo: "HPBtoMe"
Cloud Firestore から取得したオブジェクト
{ createdAt: t {seconds: 1618557497, nanoseconds: 367000000}, dueDate: t {seconds: 1618730280, nanoseconds: 0}, isDone: false, title: "HPBtoMe", }
new Date(seconds) した場合
data.dueDate.seconds; // => 1618730280 new Date(data.dueDate.seconds); // => Tue Jan 20 1970 02:38:50 GMT+0900
Cloud Firestore 上に登録されている dueDate
は 2021年4月18日 16:18:00 UTC+9
なのですが new Date(seconds)
で変換すると 1970年1月20日 という全然異なる日付になってしまいました。なんもわからん…
toDate()
メソッドを使う
Timestamp class
toDate(): Converts a Timestamp to a JavaScript Date object. This conversion causes a loss of precision since Date objects only support millisecond precision.
Timestamp class | Firebase
import dayjs from 'dayjs'; import firebase from 'firebase/app'; import 'firebase/firestore'; const firebaseApp = firebase.initializeApp(FIREBASE_CONFIG); const db = firebaseApp.firestore(); // … const [todoList, setTodoList] = useState([]); const getTodoFromFirebase = async () => { const items = await db .collection(COLLECTION_NAME) .orderBy('dueDate') .get(); setTodoList(items.items.map((item) => {id: item.id, ...item.data()})); }; //... return ( <ul> {todoList?.map((todo) => { const dueDate = dayjs(todo.dueDate.toDate()); // ← ココ return ( <li key={todo.is}> <span>{todo.title}</span> <time datetime={dueDate.format('YYYY-MM-DDTHH:mm')}> {dueDate.format('YYYY-MM-DD')} </time> </li> ); }} </ul> )
₍ ᐢ. ̫ .ᐢ ₎👌 ヨシ!
所管
Firebase ドキュメント と ドキュメンテーションが別になってるのまじ探しにくいから何とかしておくれ… クラスとかメソッドとか書いてるドキュメンテーションは自動的によしなに日本語翻訳してくれるんだけど、メソッド名まで日本語に翻訳されちゃうから困っちゃうんよね…
とはいえ、だいぶ Firebase と仲良くなれてきた気がします!
そう。4/18 は僕の誕生日なのでみなさん祝ってください!!
欲しいものは時間と知識と不労所得です。ヨロシクオネガイシマス!!!!
[参考]
Firestore はこれが良いと聞きました!