JavaScript における日付処理の新時代の幕開け
James Reed
Infrastructure Engineer · Leapcell

はじめに
長年にわたり、JavaScript 開発者は Moment.js や Date-fns のような強力なライブラリの助けを借りて、日付と時刻の操作の複雑さを乗り越えてきました。これらのツールは、JavaScript の組み込み Date オブジェクトのギャップを埋める上で不可欠でしたが、このオブジェクトは、機能的ではあるものの、使いやすさ、不変性、タイムゾーンや国際化の処理においてしばしば不足していました。しかし、JavaScript の日付と時刻管理の状況は、大きな変革の瀬戸際にあります。Temporal API という新しい標準が登場し、精度、予測可能性、開発者フレンドリーさの新時代を到来させることが期待されています。この記事では、Temporal API が Node.js での日付と時刻の扱い方をどのように変革する可能性があり、私たちが愛用してきた従来のライブラリを不要にする可能性があるかを探ります。
Temporal の解明:モダンな日付時刻管理の深掘り
Temporal がもたらす影響を探る前に、それが導入する、そして解決するコアコンセプトを理解しましょう。
コア用語
Temporal.Instant: カレンダーシステムやタイムゾーンに依存しない、特定の日時を表します。タイムライン上の単一の絶対的な瞬間と考えてください。Temporal.ZonedDateTime:Instantに特定のタイムゾーンとカレンダーシステムを組み合わせ、特定の場所における特定の日時の人間が読める表現を提供します。Temporal.PlainDate: 時間やタイムゾーンのコンポーネントを含まない日付を表します(例:「2023年10月26日」)。時刻のコンテキストなしで、繰り返しイベントやデータベースに日付を保存する場合に便利です。Temporal.PlainTime: 日付やタイムゾーンのコンポーネントを含まない一日の時刻を表します(例:「14:30:00」)。Temporal.PlainDateTime:PlainDateとPlainTimeの組み合わせで、タイムゾーンのコンポーネントを含みません(例:「2023年10月26日 14:30:00」)。Temporal.PlainYearMonth: 日付、時刻、タイムゾーンを含まない年と月を表します(例:「2023年10月」)。Temporal.PlainMonthDay: 年、時刻、タイムゾーンを含まない月と日を表します(例:「10月26日」)。Temporal.Duration: 「3時間30分」や「5日」のような特定量の時間を表します。Temporal オブジェクトに対する算術演算を実行するために使用されます。
Date の問題点と Temporal が解決策である理由
JavaScript の組み込み Date オブジェクトには、長年にわたるいくつかの問題があります。
- 可変性:
Dateオブジェクトは可変であるため、setDate()のような操作は元のオブジェクトを直接変更します。これは、特に複雑なアプリケーションにおいて、予期しない副作用やバグにつながる可能性があります。 - タイムゾーン処理:
Dateインスタンスは内部的に UTC(協定世界時)に結び付けられますが、文字列に変換される際にはローカルタイムゾーンに従って表示されるため、混乱を招き、国際的なアプリケーションでは注意深い処理が必要です。 - 曖昧さ: 文字列表現の解析が JavaScript エンジン間で一貫せず、実装定義の動作に大きく依存することがあります。
- 具体性の欠如: 「日付」と「特定のタイムゾーンにおける日付と時刻」の明確な区別がなく、開発者が目的の結果を得るために文字列操作と
Dateオブジェクトを組み合わせて使用することがよくあります。 - 算術の複雑さ: 特定の日数、月数、または年数を加算するような複雑な日付算術、特にタイムゾーンの境界や夏時間変更をまたぐ場合、実行が困難でエラーが発生しやすいことが知られています。
Temporal は、そのオブジェクト指向設計と不変性および明示性への注力により、これらの問題に直接対処します。
原則:不変性と連鎖的な操作
Temporal の基本原則の 1 つは不変性です。すべての Temporal オブジェクトは不変であり、日数 の加算やタイムゾーンの変更のような操作は、元のオブジェクトを変更するのではなく、新しい Temporal オブジェクトを返します。これにより、予測可能性が大幅に向上し、バグが減少します。
日数を加算することを検討してください。
// Moment.js (可変) を使用 const momentDate = moment('2023-10-26'); momentDate.add(5, 'days'); // momentDate は '2023-10-31' になる // Temporal (不変) を使用 const plainDate = Temporal.PlainDate.from('2023-10-26'); const newPlainDate = plainDate.add({ days: 5 }); // plainDate は '2023-10-26' のまま、newPlainDate は '2023-10-31' になる console.log(plainDate.toString()); // 2023-10-26 console.log(newPlainDate.toString()); // 2023-10-31
明示的なタイムゾーンとカレンダー処理
Temporal は、タイムゾーンとカレンダーシステムの選択を明示的に行います。暗黙的な変換の代わりに、ZonedDateTime がどのタイムゾーンを参照しているかを常に把握できます。
// ZonedDateTime の作成 const nowInLondon = Temporal.ZonedDateTime.from({ year: 2023, month: 10, day: 26, hour: 14, minute: 30, timeZone: 'Europe/London' }); console.log(nowInLondon.toString()); // 2023-10-26T14:30:00+01:00[Europe/London] // 別のタイムゾーンへの変換 const nowInTokyo = nowInLondon.withTimeZone('Asia/Tokyo'); console.log(nowInTokyo.toString()); // 2023-10-26T22:30:00+09:00[Asia/Tokyo] // タイムゾーンをまたぐ計算 const futureInLondon = nowInLondon.add({ days: 1 }); console.log(futureInLondon.toString()); // 2023-10-27T14:30:00+01:00[Europe/London]
タイムゾーンを変更する際に時間が正しく調整され、正確な表現が保証されていることに注意してください。
Temporal.Duration による堅牢な日付算術
Temporal.Duration は、正確で曖昧さのない日付算術を可能にします。
const birthDate = Temporal.PlainDate.from('1990-05-15'); const today = Temporal.PlainDate.from('2023-10-26'); // 差の計算 const ageDuration = birthDate.until(today); console.log(`Duration: P${ageDuration.years}Y${ageDuration.months}M${ageDuration.days}D`); // Duration: P33Y5M11D // Duration の加算 const fiveDaysThreeHours = Temporal.Duration.from({ days: 5, hours: 3 }); const plainDateTime = Temporal.PlainDateTime.from('2023-10-26T10:00:00'); const futureDateTime = plainDateTime.add(fiveDaysThreeHours); console.log(futureDateTime.toString()); // 2023-10-31T13:00:00
この明示的な Duration オブジェクトは、従来のライブラリの曖昧な add または subtract メソッドの落とし穴を回避します。ここでは add(1, 'month') が月末に予期しない動作をする可能性があります(例:1月31日に1ヶ月加算すると、ライブラリのロジックによって2月28日/29日または3月3日になる可能性があります)。Temporal はこれらの「カレンダー認識」操作を適切に処理します。
Node.js での適用
Temporal API は現在 Stage 3 の TC39 提案であり、ほぼ最終段階にあり、実装が利用可能です。Node.js では、ポリフィル(temporal-polyfill のようなもの)を使用するか、公式に統合されたら新しい Node.js バージョンで実験的な機能を有効にすることで、これを試すことができます。
Node.js バックエンドでは、Temporal は以下に役立ちます。
- タスクのスケジュール設定: 異なるタイムゾーンで cron ジョブや遅延タスクを正確にスケジュール設定します。
- データベースとのやり取り: さまざまな地理的場所のユーザーを扱う場合に、日付時刻を正確に保存および取得します。
- API 開発: API レスポンスで一貫した日付時刻フォーマットと計算を保証します。
- ログ記録と監査: ローカルサーバー設定の影響を受けない、絶対的な精度でのイベントのタイムスタンプ付け。
たとえば、e コマースプラットフォームがニューヨークで午前 9 時、ロンドンで午後 2 時、東京で午後 10 時にプロモーションを開始するようにスケジュールする必要がある場合、Temporal の ZonedDateTime を使用すると、これらの変換と比較が簡単かつ信頼性が高くなり、隠れた複雑さがなくなります。
Moment.js および Date-fns からの移行
Moment.js と Date-fns はコミュニティに役立ってきましたが、元の Date オブジェクトの設計に根ざしたアーキテク チャ上の限界を本質的に持っているか、それらを抽象化しようとしています。特に Moment.js は、新しい機能の開発が停止されており、開発者に代替手段を探すことを推奨しています。Date-fns はモダンで不変ですが、Temporal がプラットフォームレベルで解決しようとしている哲学的な課題のいくつかに依然として直面しています。
ブラウザおよび Node.js のネイティブ API である Temporal は、以下を約束します。
- バンドルサイズのオーバーヘッドなし:サードパーティライブラリを含める必要がなく、アプリケーションサイズを削減できます。
- パフォーマンス: ネイティブ実装は、ユーザランドのポリフィルやライブラリよりも一般的に高速です。
- 標準化: すべての JavaScript 環境で普遍的に理解され、一貫して動作する API。
結論
Temporal API は、単なる日付時刻ライブラリではありません。JavaScript が日付と時刻をどのように処理するかという根本的な再考です。Temporal は、インスタント、日付、時刻、および期間を処理するための包括的で不変かつ明示的なオブジェクトセットを提供することにより、Node.js およびより広範な JavaScript エコシステムにおける日付時刻管理に、切望されていた精度と予測可能性をもたらします。日付と時刻の悪夢が過去の遺物となる未来に備える時が来ました。Temporal が開発のこの重要な側面を標準化し、簡素化するために登場します。

