メインコンテンツまでスキップ

Date

Dateは時刻のためのJavaScriptの読み込みクラスです。DateオブジェクトはUTC(協定世界時)の1970/01/01からの経過ミリ秒を表す数値を含んでいます。

はじめに、Dateオブジェクトについて

JavaScriptの組み込みDateオブジェクトの使用にはいくつかの注意が必要です。次に、主な問題点を挙げます。

  1. 非直感的な動作: Dateオブジェクトは、常識的には存在しない日付を解析しようとすると自己補正を試みます。たとえば、存在しない日付である2月30日をDateオブジェクトとして表現しようとすると、JavaScriptはこれを3月1日に補正します。これは読み手に混乱をもたらし、予期しない結果を生む可能性があります。
  2. フォーマットが手間: Dateオブジェクトを特定のフォーマットで表示するためには、しばしば独自のフォーマット関数を作成する必要があります。これは手間がかかるだけでなく、バグの原因ともなり得ます。
  3. タイムゾーンの扱い: JavaScriptのDateオブジェクトは、常にローカルタイムゾーンで時間を表示します。しかし、ユーザーが世界中のさまざまな時間帯に分散している場合、これは非常に混乱を招きます。

以上のような問題を解決するために、date-fnsDay.jsのようなサードパーティのライブラリの使用を推奨します。これらのライブラリは、シンプルで一貫したAPIと豊富な日付操作関数を提供し、タイムゾーンの問題を適切に処理します。また、日付を表示するための多くのフォーマットオプションも提供します。

したがって、シンプルなタスクにはJavaScriptの組み込みDateオブジェクトが適していますが、より複雑な日付や時間の操作が必要な場合は、適切なサードパーティのライブラリを選択することを検討してください。これにより、日付と時間に関連する操作がより確実で効率的になります。

サードパティーの日付ライブラリ

date-fns

オブジェクトというよりは関数として日付の操作をします。直接Dateオブジェクトを操作する上での煩わしい点をカバーします。

Day.js

軽量な日付操作のためのオブジェクトを提供します。後述するMoment.jsとAPIに互換性があり、Moment.jsを使っているプロジェクトでの乗り換え先に検討されることがあります。

Moment.js

日付操作のためのパッケージとして絶大な知名度がありますが現在は新規開発は行われておらず、積極的に新規プロジェクトで導入する必要はありません。

Dateの操作

年を取得する - Date.prototype.getFullYear()

年を取得します。誤ってDate.prototype.getYear()を使用しないでください。

年の下2-3桁を取得する - Date.prototype.getYear()

非推奨です。与えられた日付の年数を表す数値から1900を引いた値を返します。代わりにDate.prototype.getFullYear()を使ってください。

月を取得する - Date.prototype.getMonth()

月を取得しますが、0-11を返すため実際の月にするためには1を加算してください。

日を取得する - Date.prototype.getDate()

日を取得します。誤ってDate.prototype.getDay()を使用しないでください。

曜日を取得する - Date.prototype.getDay()

曜日を取得します。0-6を返します。0が日曜日、1が月曜日のようになっています。

時を取得する - Date.prototype.getHours()

時を取得します。

分を取得する - Date.prototype.getMinutes()

分を取得します。

秒を取得する - Date.prototype.getSeconds()

秒を取得します。

ミリ秒を取得する - Date.prototype.getMilliseconds()

ミリ秒を取得します。

UTC 1970/01/01 00:00:00からの経過ミリ秒を取得する - Date.prototype.getTime()

協定世界時の1970/01/01 00:00:00からの経過ミリ秒単位の数値で返します。

ISO8601に準じた文字列に変換する - Date.prototype.toJSON()

ISO8601に準じた文字列を返します。ISO8601はYYYY-MM-DDThh:mm:ss.sssZの形式です。

コラム: Dateの問題点の由来

Dateの設計はとてもプリミティブであるため、yyyy年m月d日のような一般的な日付書式への変換には少なくないコードが必要です。

Dateの日付フォーマット処理
ts
const d = new Date();
const year = d.getFullYear();
const month = d.getMonth() + 1;
const day = d.getDate();
console.log(`${year}${month}${day}日`);
Dateの日付フォーマット処理
ts
const d = new Date();
const year = d.getFullYear();
const month = d.getMonth() + 1;
const day = d.getDate();
console.log(`${year}${month}${day}日`);

他にもDateにはタイムゾーンの具体的な識別(例:'America/Los_Angeles')や、タイムゾーンの変換に便利なメソッドがありません。使い勝手の悪さから、Moment.jsdate-fnsといったサードパーティの日付ライブラリにお世話になった人も多いのではないでしょうか。あまりの不評もあって、Temporalというモダンな日付ビルトインAPIも検討されはじめています。

ところで、Dateはどうしてこのような微妙な実装になっているのでしょうか。これには歴史が関係します。JavaScriptを実装するのにブレンダン・アイク氏に与えられたのは、わずか10日だったそうです。この工期には日付処理の実装も含まれていました。日付処理は複雑でフルスクラッチで作ったら時間がかかるものです。工期短縮のため、実装は当時のJavaのjava.util.Dateから移植されることになりました1

Javaの日付処理を知っている人なら「Java由来なら、どうしてこんなひどい実装になったんだ!?」と思われるかもしれません。今のJavaの日付処理はとても立派なものです。実は、当時のJavaのjava.util.Dateは今のJavaの日付処理とは、全然異なるものだったのです。それは評判の良くないものだったそうです。

当時のJava(1.0系)のjava.util.Dateのドキュメント。見てみると、たしかにJavaScriptのDateとインターフェースがそっくりです。移植されたというのが、ここからも垣間見えます。

Java(1.0系)のjava.util.Dateのリファレンスには、JavaScriptのDateと似たようなインターフェイスが並ぶ

あまりにもそっくり移植されてしまったため、2000年問題のバグまで引き継いでしまったそうです2

2000年問題の「バグ」をjava.util.Dateから引き継いだと指摘するMozillaによるスライド

2000年問題のバグ
js
console.log(new Date(1999, 3, 1).getYear());
99
console.log(new Date(2000, 3, 1).getYear());
100
2000年問題のバグ
js
console.log(new Date(1999, 3, 1).getYear());
99
console.log(new Date(2000, 3, 1).getYear());
100

バグと言いましたが、今となっては仕様になっています

Javaでは1.0のjava.util.Dateが良くなかったため、Java 1.1のリリースですぐに非推奨になり、新しい日付処理に置き換えられていきました。その結果、Javaの日付ライブラリは十分に使いやすいものになっています。Javaを真似したJavaScriptはその後どうなったかというと、20年以上Dateはそのままです。