6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

2022年3月16日 Date (JavaScript Primer)

復習

オプショナルチェーン演算子とは

以下の二つのコードが同義です。

obj?.value
obj != null ? obj.value : undefined
  • レシーバがnull undefined のときにエラーではなくundefined を返します。
  • 三項演算子で書くよりもリファクタリングができます。

Dateオブジェクト

ECMAScriptで定義されたビルトインオブジェクトです。

  • Dateにおける「時刻」は、UTC協定世界時)の1970年1月1日0時0分0秒を基準とした相対的なミリ秒として保持されます。
  • Dateオブジェクトのインスタンスはそれぞれがひとつの時刻値を持ち、その時刻値を元に日付や時・分などを扱うメソッドを提供します。

JSTとは 日本時間として普通に使っている時間

UTCとは 今の世界で標準時として使っている時間 (日本時間から9時間引いた時間)

インスタンスの作成

Dateオブジェクトのインスタンスは、常にnew演算子を使って作成します。 インスタンスの作成は大きく分けて2種類あります。

現在の時刻をインスタンス

newするときにコンストラクタ引数を何も渡さない場合は、現在の時刻を表すインスタンスが作成されます。

const now = new Date();
console.log(Date.now()); // => 1647384533248

// 時刻値を取得する
console.log(now.getTime()); // => 1647384533248
// 時刻をISO 8601形式の文字列で表示する
console.log(now.toISOString()); // =>2022-03-15T22:49:11.841Z
  • getTimeメソッドはインスタンスが持つ時刻値を表します。
  • Date.now()UTC (協定世界時) での 1970 年 1 月 1 日 0 時 0 分 0 秒 から現在までの経過時間をミリ秒単位で返します。(インスタンスではなくclassのメソッドです)
  • toISOStringメソッドは、時刻をUTCにおけるISO 8601形式の文字列に変換できます。 ISO 8601とは国際規格となっている文字列の形式で、2006-01-02T15:04:05.999+09:00のように時刻を表現します。(わかりやすいためよく使われます)

任意の時刻をインスタンス

インスタンス生成時にコンストラクタ引数を渡すことで、任意の時刻を指定する3つの方法があります。

  1. 時刻値を渡すもの
  2. 時刻を示す文字列を渡すもの
  3. 時刻の部分(年・月・日など)をそれぞれ数値で渡すもの

1. 時刻値を渡すもの

コンストラクタ関数にミリ秒を表す数値型の引数を渡したときに適用されます。 渡した数値をUTCの1970年1月1日0時0分0秒を基準とした時刻値として扱います。 この方法は実行環境による挙動の違いが起きないので安全です。 また、時刻値を直接指定するので、他の2つの方法と違ってタイムゾーンを考慮する必要がありません。

const now = Date.now();
console.log(now); // => 1647385122932

const now2 = new Date(now);
console.log(now2); // => 2022-03-15T22:58:42.933Z
  • 実行タイミングによって数値は変わります。
  • new Dateのコンストラクタ引数にDate.now()メソッドでミリ秒を取得し渡しています。

2.ISO形式の文字列を引数に渡す

// UTCにおける"2006年1月2日15時04分05秒999"を表すISO 8601形式の文字列
const inUTC = new Date("2006-01-02T15:04:05.999Z");
console.log(inUTC.toISOString()); // => "2006-01-02T15:04:05.999Z"

// 上記の例とは異なり、UTCであることを表す'Z'がついていないことに注意
// Asia/Tokyo(+09:00)で実行すると、UTCにおける表記は9時間前の06時04分05秒になる
const inLocal = new Date("2006-01-02T15:04:05.999");
console.log(inLocal.toISOString()); // "2006-01-02T06:04:05.999Z" (Asia/Tokyoの場合)
  • ZをつけることでUTCタイムゾーンを指定しているので、つけないと実行環境に依存します。

3. 時刻を次のように、年・月・日などの部分ごとの数値で指定する方法です。

new Date(year, month, day, hour, minutes, seconds, milliseconds);
  • 月は0〜11になる点がポイントです。
  • 日付だけは1がデフォルトで渡されます。
  • タイムゾーンを指定することが出来ないため、常にローカルのタイムゾーンの時刻とみなされ結果が実行環境に依存します。

この方法でUTCを指定するためにはDate.UTCメソッドを使えば良いです。

const ms = Date.UTC(2006, 0, 2, 15, 4, 5, 999);
// 時刻値を渡すコンストラクタと併用する
const date2 = new Date(ms);
console.log(date2.toISOString()); // => "2006-01-02T15:04:05.999Z"

不正な引数を渡した場合、以下のようにNaNが返されます。

(どのオーバーロードにも当てはまらない引数や、時刻としてパースできない文字列を渡した場合)

オーバーロードとは・・・「引数や戻り値が異なるが名称が同一のメソッドを複数定義する」というオブジェクト指向プログラミングのテクニックである。

const invalid = new Date("");
console.log(invalid.getTime()); // => NaN
console.log(invalid.toString()); // => "Invalid Date"

Dateのインスタンスメソッド

Dateオブジェクトのインスタンスは多くのメソッドを持っていますが、 ほとんどはgetHoursとsetHoursのような、時刻の各部分を取得・更新するためのメソッドです。

次の例は、日付を決まった形式の文字列に変換しています。 getMonthメソッドやsetMonthメソッドのように月を数値で扱うメソッドは、0から11の数値で指定することに注意しましょう。あるDateのインスタンスの時刻が何月かを表示するには、getMonthメソッドの返り値に1を足す必要があります。

// YYYY/MM/DD形式の文字列に変換する関数
function formatDate(date) {
    const yyyy = String(date.getFullYear());
    console.log(typeof yyyy); // => string
    // Stringの`padStart`メソッド(ES2017)で2桁になるように0埋めする
    const mm = String(date.getMonth() + 1).padStart(2, "0");
    console.log(mm); // => 01
    const dd = String(date.getDate()).padStart(2, "0");
    return `${yyyy}/${mm}/${dd}`;
}

const date = new Date("2006-01-02T15:04:05.999");
console.log(formatDate(date)); // => "2006/01/02"

getTimezoneOffsetメソッド

実行環境のタイムゾーンUTCからのオフセット値を分単位の数値で返します。

オフセットとは・・・位置を基準点からの距離で表した値です。 ここではUTCと9時間差がありますのでそれを分単位にするため、返り値が540になります。それを○時間という単位で表すため60で割っています。

// getTimezoneOffsetはインスタンスメソッドなので、インスタンスが必要
const now = new Date();
// 時間単位にしたタイムゾーンオフセット
const timezoneOffsetInHours = now.getTimezoneOffset() / 60;
// UTCの現在の時間を計算できる
console.log(`Hours in UTC: ${now.getHours() + timezoneOffsetInHours}`);

現実のユースケースとDate

ここまでDateオブジェクトとインスタンスメソッドについて述べましたが、 多くのユースケースにおいては機能が不十分です。 たとえば次のような場合に、Dateでは直感的に記述できません。

  • 任意の書式の文字列から時刻に変換するメソッドがない
  • 「時刻を1時間進める」のように時刻を前後にずらす操作を提供するメソッドがない
  • 任意のタイムゾーンにおける時刻を計算するメソッドがない
  • YYYY/MM/DDのようなフォーマットに基づいた文字列への変換を提供するメソッドがない

    そのため、JavaScriptにおける日付・時刻の処理は、標準のDateではなくライブラリを使うことが一般的になっています。 代表的なライブラリとしては、moment.jsやjs-joda、date-fnsなどがあります。

  • Date自体は実際に使うとなると変換できなかったり操作できないのでライブラリを用いると良いでしょう。

以下、ライブラリを用いた例です。

// moment.jsで現在時刻のmomentオブジェクトを作る
const now = moment();
// addメソッドで10分進める
const future = now.add(10, "minutes");
// formatメソッドで任意の書式の文字列に変換する
console.log(future.format("YYYY/MM/DD"));

まとめ

この章では、Dateオブジェクトについて学びました。

  • Dateオブジェクトのインスタンスはある特定の時刻を表すビルトインオブジェクト
  • Dateにおける「時刻」は、UTC協定世界時)の1970年1月1日0時0分0秒を基準とした相対的なミリ秒として保持されている
  • Dateコンストラクタで任意の時間を表すDateインスタンスを作成できる
  • Dateインスタンスメソッドにはさまざまなものがあるが、現実のユースケースでは機能が不十分になりやすい
  • ビルトインオブジェクトのDateのみではなく、ライブラリも合わせて利用するのが一般的

参考

Date (JSprimer)

Date.now()

String()コンストラクタ

String.prototype.padStart()