トラック
/
JavaScript
JavaScript
/
演習
/
予約の時間
予約の時間

予約の時間

学習演習

はじめに

JavaScriptには、日時を保持し、その管理のためのメソッドを提供する組み込みオブジェクトDateがあります。

Caution

DateはJavaのjava.util.Dateクラスを基にしています。このクラスは2010年代初頭に置き換えられましたが、後方互換性のために、JavaScriptのDateは今も残っています。

一般にDateの扱いは難しく、タイムゾーンの処理も不十分か、まったく存在しないため、moment.js、day.js、date-fns、luxonなど、多くのライブラリが存在します。 これらのライブラリは、Exercismでは利用できません。

自分のプロジェクトでは、moment.jsのような非推奨・メンテナンスされていないパッケージは使わず、luxonのようなよりモダンな代替手段や、まだ広く利用できないTemporalに頼りましょう。 この演習ではDateに焦点を当てます。DateはJavaScriptが続く限り、ずっと重要であり続けます。

作成

Dateオブジェクトは、Dateクラスのインスタンスです。 コンストラクター関数に引数を渡さずに作成することもできます。 こうすると、現在の日時を表すDateオブジェクトが得られます。

const now = new Date();
// => Thu Apr 14 2022 11:46:08 GMT+0530 (India Standard Time)
// Shows current day, date and time (in your time zone).

Unixタイムスタンプ(数値)

数値を渡すと、それはtimestampとして解釈されます。 タイムスタンプは、1970年1月1日 UTC+0から経過したミリ秒数を表す整数です。

const epoch = new Date(0);
// Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)

const another = new Date(1749508766627);
// Tue Jun 10 2025 00:39:26 GMT+0200 (Central European Summer Time)

new Date(0)が「最も早い」日付オブジェクトを生成すると期待するかもしれません。しかしJavaScriptは日付をローカルのタイムゾーンに変換するため、実際にUnixエポックの値を得るのは、GMT / UTC+0のタイムゾーン付近にいる人だけです。

ISO 8601タイムスタンプ(文字列)

日付を表す文字列の値を、Dateコンストラクターに渡すことができます。 実装間で一貫している唯一の形式は、国際的に認識され標準化された、いわゆるISO 8601タイムスタンプ文字列の簡略版です。

UTCでのある時点は、次のように表されます。

YYYY-MM-DDTHH:mm:ss.mssZ
YYYYMMDDTHHmmss.mssZ

各部分は次のように置き換わります。

キー 説明 デフォルト
YYYY 暦年、4桁で表記
MM 暦月、2桁で表記 01
DD 暦日、2桁で表記 01
T 文字そのままのT。日付と時刻を区切ります
HH 24時間制の時、2桁 00
mm 分、2桁 00
ss 秒、2桁 00
mss ミリ秒、3桁 000
Z 文字そのままのZ、またはオフセット+/-HH:mm

文字そのままのZはUTCを表します(タイムゾーンなし、夏時間なし)。

ほとんどの要素にはデフォルト値があるので、末尾の部分を省略してもかまいません。

YYYY-MM-DD

時刻はデフォルトで00:00:00.000になります。

タイムスタンプがZで終わらず、タイムゾーンのオフセットを示す+HH:mmや-HH:mmでも終わらない場合、歴史的な理由から、次のことが当てはまります。

タイムゾーンのオフセットがない場合、日付のみの形式はUTC時刻として解釈され、日付と時刻の形式はローカル時刻として解釈されます。 UTC時刻としての解釈は、ISO 8601と整合しない歴史的な仕様の誤りによるものですが、ウェブの互換性のために変更できませんでした。 詳しくはBroken Parser – A Web Reality Issueを参照してください。

Caution

Date.parseが受け付けるその他の形式は、動くことも動かないこともあります。 JavaScriptでDateを扱うときは、stringからDateに変換する際には_必ず_ISO 8601タイムスタンプを使いましょう。

日付のみの形式は許可されていますが、すべてのISO 8601形式がサポートされているわけではありません。 MDNの簡略版の説明ページを参照してください。

Dateオブジェクト

既存のDateオブジェクトをコンストラクターの引数として使うこともできます。 こうすると、同じ日時を持つ既存のDateオブジェクトのコピーが作られます。

const t1 = new Date();
const t2 = new Date(t1);
// Values of t1 and t2 will be the same.

日付と時刻の各要素の値を個別に指定する

日付だけを表すDateは、数値を3つ渡して作成できます。 日付と時刻を表すDateは、数値を6つ渡して作成できます。

const date1 = new Date(95, 11, 17);
// Creates Date for Dec 17 1995 00:00 if your local timezone is equivalent to UTC.

const date2 = new Date(2013, 12, 5, 13, 24, 0);
// Creates Date for Jan 5 2014 13:24 if your local timezone is equivalent to UTC.

2番目の値はmonthで、1月が0から始まり、12月が11になります。

Date.parse()

日付をパースする関数Date.parseへの言及や参照を見かけることがあるかもしれません。 この関数には不変の性質(常に成り立つこと)がわずかしかなく、残りの実装は仕様で定められていない(したがって標準ではない)ため、使うべきではありません。

Dateの要素にアクセスする

Dateオブジェクトには、日付の要素を返すさまざまなメソッドがあります。

getFullYear(); // Get the year (4 digits)
getMonth(); // Get the month, from 0 to 11.
getDate(); // Get the day of month, from 1 to 31.
getHours(); // Get the hour in a 24 clock, from 0 to 23
getMinutes(); // Get the minutes, from 0 to 59
getSeconds(); // Get the seconds, from 0 to 59
getMilliseconds(); // Get the milliseconds, from 0 and 999
getDay(); // Get the day of week, from 0 (Sunday) to 6 (Saturday).

これらのそれぞれには、値を更新するための対応するset版(例:setFullYear)があります。 あふれた値は、次の要素に繰り越されます。

const date = new Date('2025-02-28T12:42:00Z');
// => Fri Feb 28 2025 13:42:00 GMT+0100 (Central European Standard Time)

date.setDate(29);
// there was no February 29th in 2025.

date.getDate();
// => 1

date.toString();
// => Sat Mar 01 2025 13:42:00 GMT+0100 (Central European Standard Time)

すべてのメソッドには、ローカルのタイムゾーンを無視するUTC版があります。

日付からの変換

Dateオブジェクトには、UNIXタイムスタンプをミリ秒で返すメソッドgetTime()があります。つまり、1970年1月1日UTCの午前0時からのミリ秒数です。 さらに、DateオブジェクトをISO 8601タイムスタンプ文字列に変換するメソッドtoISOString()も利用できます。

Dateの比較

より大きい(>)と以上(>=)、およびより小さい(<)と以下(<=)は、2つのDateの間、またはDateと数値の間で直接使えます。 これは、JavaScriptがDateをプリミティブに変換しようとするために機能します。

Advanced

2つのDateの間、またはDateと数値の間で比較を行うとき、JavaScriptは[Symbol.toPrimitive]("number")を呼び出し、その内部でdate.valueOf()を呼び出します。 後者はdate.getTime()を呼び出すのと同じです。

この動作に頼りたくない場合は、先にgetTime()を使って数値に変換しましょう。

Dateは等価(==や===)では比較できませんが、.getTime()の結果なら比較できます。

説明

この演習では、予約を管理するためのいくつかの関数に取り組みます。 システムはすべてをISO 8601形式の文字列で保存しますが、人がカレンダーを使うときの感覚とは違います。 さまざまな形式の間で変換するには、複数の関数が必要です。

1. 予約を作成しましょう

現在時刻からn日後に予約を作成します。 この関数はn日を受け取り、n日後の予約時刻を返します。

createAppointment(4, now);
// Given now is Sun Oct 05 2022 23:28:43 GMT+0600 (Bangladesh Standard Time)
// => Sun Oct 09 2022 23:28:43 GMT+0600 (Bangladesh Standard Time)

2番目の仮引数nowを使わない場合は、代わりに現在時刻を使います。

2. 日付をタイムスタンプに変換しましょう

さまざまなツールは、国際標準のISO 8601形式でしか扱えません。 日付を受け取って、その形式の文字列を返す関数getAppointmentTimestampを書きます。

const appointment = new Date(Date.UTC(2010, 6, 16, 12, 42, 0, 0));

getAppointmentTimestamp(appointment);
// => '2010-07-16T12:42:00.000Z'

3. 予約の詳細を取得しましょう

タイムスタンプは読みにくいものです。予約の詳細を取得する関数があると、その助けになります。 関数getAppointmentDetailsはISO 8601形式のタイムスタンプを受け取り、年、月、日、時、分を返します。

getAppointmentDetails('2022-04-24T08:15:00.000');
// => { year: 2022, month: 3, date: 24, hour: 8, minute: 15 }

4. 指定されたオプションで予約を更新しましょう

この関数は、第1引数に予約時刻、第2引数にいくつかのオプションを持つオブジェクトを受け取ります。 オブジェクト内のオプションに従って予約を更新し、新しい予約日時を返します。 オプションオブジェクトには複数のオプションを指定できます。

updateAppointment('2022-02-09T09:20:00.000', { month: 6 });
// => { year: 2022, month: 6, date: 9, hour: 10, minute: 20 }

5. 2つの予約間の空き時間を取得しましょう

この関数は、2つの予約(タイムスタンプ)を引数として受け取ります。 2つの時刻の差を秒で返します。

0.5秒はほとんど意味がないので、返す前に数値を丸めます。

timeBetween('2022-12-12T09:20:00.000', '2022-12-18T08:30:00.000');
// => 515400

6. 予約が現在有効かどうかを確認しましょう

最後に、予約が作成されると、システムはそれが有効かどうかを確認する必要があります。 つまり、予約は未来の時刻でなければならず、過去の時刻であってはなりません。

2つの引数、予約のタイムスタンプ(文字列)と現在時刻のタイムスタンプ(文字列)を受け取り、現在時刻を基準にして予約が未来であればtrueを返す関数isValidを書きます。

isValid('2022-02-11T23:00:00.000', '2022-02-08T23:00:00.000');
// => true
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
JavaScript Exercism

予約の時間を始める準備はできましたか?

Exercismに登録すれば、37個のコンセプト159個の演習、そして本物の人間によるメンタリングとともに、JavaScriptを学んでマスターできます。すべて無料です。