日付ライブラリTempoを触ってみた(date-fnsと比較)

はじめに
こんにちは、フロントエンドエンジニアの堀江(@nandemo_3_)です。
先日、JavaScriptの新たな日付ライブラリがTempoがリリースされました。
2023/2/26にv0.0.13がリリースされたばかりです。
リリース3日後でStar数が1700になっており、今後の伸びが期待されるところです。
お決まりの既存の類似ライブラリとStar数を比べた画像はこちらです。

あまり情報がないので、触りながら色々試していこうと思います。
Tempoの特徴
Tempoは、JavaScriptの日付と時刻のライブラリの誇り高き伝統の中の新しいライブラリです。
moment.js、day.js、date-fnsなどにインスパイアされたTempoは、可能な限り小さく使いやすいように一から作られています。
Tempoは、ネイティブのDateオブジェクトを扱うためのユーティリティ・コレクションと考えるのが最適です。
Tempoは、JavaScriptのIntl.DateTimeFormatを利用して、タイムゾーンオフセットやロケールを意識した日付フォーマットのような複雑なデータを抽出し、日付のフォーマット、解析、操作を行うシンプルなAPIを提供します。
(ドキュメントから抜粋)
セットアップ
早速プロジェクト作成していきます。
今回はBunを使っていきます。
結論、BunはNode.jsと互換性があるので、Tempoも問題なく使えました。
$ mkdir tempo-sample $ cd tempo-sample $ bun init bun init helps you get started with a minimal project and tries to guess sensible defaults. Press ^C anytime to quit package name (tempo-sample): entry point (index.ts): Done! A package.json file was saved in the current directory. + index.ts + .gitignore + tsconfig.json (for editor auto-complete) + README.md To get started, run: bun run index.ts
ライブラリのインストール
続いて、Tempoをインストールしていきます。
比較のため、date-fnsもインストールします。
Tempoは軽量と言われていますが、確かにインストールがdate-fnsよりも半分の時間で完了しました。
Tempoの場合
$ bun install @formkit/tempo bun add v1.0.7 (b0393fba) installed @formkit/tempo@0.0.13 1 package installed [947.00ms]
date-fnsの場合
$ bun install date-fns bun add v1.0.7 (b0393fba) installed date-fns@3.3.1 1 package installed [1.85s]
2種類のフォーマットタイプ
フォーマットはformat関数を使います。
そして、フォーマットタイプがFormat stylesとFormat tokensの2つ用意されています。
引数の値を変えるだけで、フォーマットタイプを選ぶことができます。
Format styles
Format stylesは、Intl.DateTimeFormatを用いて、言語に依存した日付、時刻を取得することができます。
format関数の第2引数fomatにfullやlongなどを指定すると対応したフォーマットの日付が出力されます。
そして、第3引数localeに言語タイプを指定すると、その言語に合わせたフォーマットとなります。
日本語に対応しているのは嬉しいですね。
import { format } from "@formkit/tempo";
const date = new Date();
// 同じ結果
format(date, { date: "full" }, "en"); // Thursday, February 29, 2024
format(date, "full", "en"); // Thursday, February 29, 2024
// 日本語
format(date, "full", "ja"); // 2024年2月29日 木曜日
format(date, "long", "ja"); // 2024年2月29日
format(date, "short", "ja"); // 2024/02/29
また、時刻を表示する場合は、第2引数fomatをobject型にします。
{ date: "long", time: "short" }のようにすれば、日付と時刻が出力されます。
import { format } from "@formkit/tempo";
const date = new Date();
format(date, { date: "long", time: "short" }, "en"); // February 29, 2024 at 9:08 PM
format(date, { date: "long", time: "short" }, "ja"); // 2024年2月29日 21:03
Format tokens
続いて、Format tokensは、表示したいフォーマットが決まっている場合に使います。
date-fnsと同じですね。
Tempoの場合
format(date, "YYYY-MM-DD", "en"); // 2024-02-29
date-fnsの場合
import { format } from "date-fns";
format(new Date(), "yyyy年MM月dd日 HH:mm"); // 2024年02月29日 21:27
タイムゾーン設定
Tempoはデフォルトで、タイムゾーンを設定できます。
date-fnsはdate-fns-tzをいう別のライブラリをインストールする必要があり一手間必要ですが、Tempoは追加プラグインなしです。
これは地味に大きいのではないでしょうか。
import { format } from "@formkit/tempo";
const date = new Date();
// February 29, 2024 at 4:42 AM
format({
date: date,
format: { date: "long", time: "short" },
locale: "en",
tz: "America/Los_Angeles",
})
// 2024年2月29日 21:42
format({
date: date,
format: { date: "long", time: "short" },
locale: "ja",
tz: "Asia/Tokyo",
})
文字列の日付のフォーマット
最後に、ISOとUTCの文字列をフォーマットをしてみました。
ISOは問題なく変換されましたが、UTCはエラーとなりました。
import { format } from "@formkit/tempo";
const isoDate = new Date().toISOString(); // 2024-02-29T13:04:11.530Z
const utcDate = new Date().toUTCString(); // Thu, 29 Feb 2024 13:04:11 GMT
// February 29, 2024 at 5:07 AM
format({
date: isoDate,
format: { date: "long", time: "short" },
locale: "en",
tz: "America/Los_Angeles",
});
// error: Non ISO 8601 compliant date (Thu, 29 Feb 2024 13:08:06 GMT).
format({
date: utcDate,
format: { date: "long", time: "short" },
locale: "ja",
tz: "Asia/Tokyo",
});
TempoはISO 8601に準拠した日付のみフォーマットするようです。
ドキュメントを調べたらコメントアウトでしれっと書いてありました。

parse関数
そういったISO 8601以外の日付文字列をフォーマットする場合にparse関数があります。
フォーマットしたい日付文字列とフォーマットを一致させると、ISO 8601に変換してくれます。
例えば、UTCの場合Thu, 29 Feb 2024 13:43:12 GMTなので、ddd, DD MMM YYYY HH:mm:ssとすればOKです。
ただ、タイムゾーンの反映はされませんでした。
import { parse, format } from "@formkit/tempo";
const isoDate = new Date().toISOString(); // 2024-02-29T13:43:12.646Z
const utcDate = new Date().toUTCString(); // Thu, 29 Feb 2024 13:43:12 GMT
// ISO
// 2024年2月29日 22:42
format({
date: isoDate,
format: { date: "long", time: "short" },
locale: "ja",
tz: "Asia/Tokyo",
});
// UTC
// 2024年2月29日 13:41
format({
date: parse(utcDate, "ddd, DD MMM YYYY HH:mm:ss"),
format: { date: "long", time: "short" },
locale: "ja",
tz: "Asia/Tokyo",
});
最後に
以上がTempoのざっくり使用感レビューでした。
詳しく仕様を知りたい方は、ドキュメントをご覧ください。
感想としては、言語タイプやタイムゾーンの設定が簡単で、date-fnsよりもシンプルなコードだったので、非常に使い勝手の良いライブラリでした。
多言語対応しているアプリケーション開発で、日付フォーマットやタイムゾーンの指定が地味に面倒くさいのではないかと思うので、
こういったパラメータ1つで対応可能なのは、エンジニアにとって非常にありがたいと思いました。
最後まで、読んでくださりありがとうございました。