SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

JavaScriptの「今」はこうなっている!現場のコードを変える注目機能を総ざらい

さらばDate、ようこそTemporal。JavaScriptの日時処理にどう向き合うか

JavaScriptの「今」はこうなっている!現場のコードを変える注目機能を総ざらい 第1回

ダウンロード サンプリング (2.4 KB)

Dateの何が悪かったのか?

 Dateとは、1995年に登場したJavaScriptの初期バージョンから存在する、日時を取り扱うための組み込みオブジェクトです。

 このDateにはいろいろな問題が指摘されてきました。そもそもDateは、JavaのDateクラスをそのまま取り入れたものとされていて、こともあろうに問題点もそっくり引き継いでしまったと言われています。これがDateの利用を難しくし、しかもバグの温床になりやすい構造を生み出してきたのです。

 具体的にどういった問題があったのでしょうか。まずは、誰もが口を揃えて指摘するDateの問題点をざっくり挙げてみましょう。

  • 月の指定が0から始まり直感的でない
  • タイムゾーン/時差の取り扱いが難しい
  • オブジェクトがミュータブル(可変)である
  • 日時文字列パースのルールが分かりにくい
  • グレゴリオ暦しか使えない
  • 精度がミリ秒単位なので、より高い精度が求められるユースケースには向かない
  • 複雑な日時計算に不向きで、他ライブラリへの依存が増える

 以降、それぞれについて、Temporalではどうなったのかも併せて、詳しく見ていきましょう。

[NOTE]JavaのDateはどうなったの?

 JavaScriptのDateのベースとなったJavaのDateクラスでは、0から始まる月、ミュータブルなオブジェクト、任意のタイムゾーンを扱えないなどの問題を言語リリース当初から抱えていました。後継のCalendarクラスでも多くの問題は解決されず、2014年リリースのJava 8においてようやく上記の問題がすべて解決されたDate and Time APIがjava.timeパッケージにて提供され、利用可能になりました。Temporalは、Date and Time APIをベースに規格化が進められたと言われています。

Dateの問題点1:月の指定が0から始まり直感的でない

 まず分かりやすいところを挙げれば、Dateでは月を表す数値が0から始まるというところでしょう。

 これはシンプルである分、切実です。日常的な感覚では月は1からなので、1月を指定しようとして1を指定して2月になってしまったり、1が得られたので"January"と置き換えてしまったりといったバグを産み出してきました。

 以下のリストでは、これを確かめています。

リスト date_month.js
const date = new Date(2026, 0, 1);
cconsole.log(date);	// Thu Jan 01 2026 00:00:00 GMT+0900 (Japan Standard Time)
const date2 = new Date(2026, 12, 1);
console.log(date2);	// Fri Jan 01 2027 00:00:00 GMT+0900 (Japan Standard Time)
const date3 = new Date(2026, 1, 29);
console.log(date3);	// Sun Mar 01 2026 00:00:00 GMT+0900 (Japan Standard Time)

 月に0を指定しましたが、これはJan(1月)と認識されます。12月を指定しようと12を与えると、翌年の1月というやや不可解な結果になります。同様に、2026年2月29日というあり得ない日付も受け入れられてしまいます。

 対処法としては、当たり前ともいえますがDateに渡す月の値を常に-1するか、new Date('2026-05-01')のように文字列でパースするといったものがあります。前者はルールを徹底できるかといった問題がありますし、後者はいささか冗長です。単純に、月を1から始めればよいのにと思いますよね。日は1からなので、一貫性についても疑問です。

Temporalでは月は1から始まり直感的

 ここから、Dateの問題点に対するTemporalの対応を見ていきましょう。Temporalでは、1月は1、12月は12というように直感的に月を表すことができます。また、あり得ない日時の指定は、以下のリストのようにエラーとなって拒否されるので安全です。

リスト temporal_month.js
const date = new Temporal.PlainDate(2026, 1, 1);
console.log(date.toString());	// 2026-01-01
console.log(date.toLocaleString());	// 1/1/2026
console.log(date.toJSON());	// 2026-01-01
const date2 = new Temporal.PlainDate(2026, 13, 1);	// error: Invalid ISO date
const date3 = new Temporal.PlainDate(2026, 2, 29);	// error: Invalid ISO date

 ここでは、コンストラクタを使ってPlainDateのインスタンスを生成しています。コンストラクタを使う場合の基本は、日時の要素を個別に引数に指定することです。必要に応じて暦情報を付加することもできます。

 なお、Temporalのインスタンスは文字列化のメソッドを揃えており、上記で使ったtoStringメソッドを含めて以下のような使い分けとなっています。

  • toString:RFC 9557フォーマットで文字列化
  • toLocaleString:現在のロケールに基づき文字列化
  • toJSON:JSON.stringfyで使うJSONを前提とした文字列化(toStringと同じ)

Dateの問題点2:タイムゾーン/時差の取り扱いが難しい

 Dateはタイムゾーン情報を持てません。正確に言うと、UTC(世界協定時)しか持てないのです。

 このため、Dateでは時差を含めたタイムゾーンの取り扱いが難しいものとなっています。Dateオブジェクトを生成すると、まずはローカルタイムゾーンに基づき日時情報が生成されます。

 ただしtoISOStringメソッドを使うと本来の日時であるUTC時間(JST-9時間)に変換されることから、あくまでもDateオブジェクトが持っているのはUTCであることが分かります。

リスト date_timezone.js
const date = new Date(2026, 5, 2, 12, 34, 56);
console.log(date.toString());	// Tue Jun 02 2026 12:34:56 GMT+0900 (Japan Standard Time)
console.log(date.toISOString());	// 2026-06-02T03:34:56.000Z

 これは、月が0から始まるといった不便さではなく、機能の欠如なので、Dateオブジェクトでタイムゾーンを取り扱うには、標準機能であるIntl.DateTimeFormatを使うか、後述する外部ライブラリを使う必要があります。特にIntl.DateTimeFormatは出力にしか使えないので、複雑な日時の計算や変換には後者のライブラリを使うのが最適解とされています。

Temporalでは時差とタイムゾーンの情報を持てる

 Temporalでは、UTC、ローカルタイムゾーンはもちろんのこと、任意のタイムゾーン、夏時間を扱うことができます。これを担うのがZonedDateTimeです。

リスト temporal_timezone.js
const str = "2026-06-02T10:00:00+09:00[Asia/Tokyo]";
console.log(Temporal.ZonedDateTime.from(str).toLocaleString());
	// 6/2/2026, 10:00:00 AM GMT+9

 ZonedDateTimeクラスのfromメソッドを使うと、後述するRFC 9557に基づく書式で構成された日時文字列からインスタンスを生成できます。リスト中の"+09:00"が時差であり、"[Asia/Tokyo]"がタイムゾーンです。以下の図に、次回で紹介する暦(カレンダー)も含めた日次文字列の書式を示します。

図:RFC 9557に基づく日時文字列
図:RFC 9557に基づく日時文字列

 タイムゾーンは、以下のコードで返される値のいずれかを指定します。

console.log(Intl.supportedValuesOf("timeZone"))

 たとえば"Asia/Tokyo"、"America/NewYork"といったものが返されますが、その数は400にも及ぶので、こちらのタイムゾーンデータベースのページなどを参照するとよいでしょう。

 なお、夏時間を導入している地域のタイムゾーン(たとえば"America/NewYork"など)を指定すると、夏時間を考慮した出力、演算が自動で実行されます。

 昨今のサーヒスは、特定の地域(たとえば日本国内)に限定して運用されるというよりは、グローバルに提供するものが増加しているので、タイムゾーンへの対応が必須といえます。

次のページ
Dateの問題点3:オブジェクトがミュータブル(可変)である

この記事は参考になりましたか?

この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/28910 2026/07/23 08:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー