MENU

【GAS】日付型 (Date オブジェクト) の独自クラスを作ろう

  • URLをコピーしました!
gas-create-datetime-class_featured-image

こんにちは、etau です 🤓

Google Apps Script (GAS) で、最初に new するオブジェクトといえば、Date オブジェクトですが (?)、 使い勝手がイマイチなところがあります。

思いついたものをいくつか書き出してみます。

  • 同じ日時の Date オブジェクトの比較が、厳密等価演算子===, 等価演算子 == でできない
  • yyyy/MM/dd の形式で値を取りたいだけなのに、コードが長くなってしまう
  • 月 (Month) の値がなぜか 0 から 11 までで取得される

このような問題に対応するために、かゆいところに手が届く独自クラスを作っていきます。

といいながら、まずは独自クラスを使わない方法をご紹介します。

目次

ライブラリを使うという選択肢

Google Apps Script にはライブラリという機能があります。

この機能を使うことによって、自分で作った関数や、別の方が公開している関数を利用することができます。

とっても、ありがたいですね。

Date オブジェクト関連のライブラリでいうと、この 2 つが有名です。

あわせて読みたい
Day.js · 2kB JavaScript date utility library 2kB JavaScript date utility library
あわせて読みたい

後者の Moment.js については、すでに開発が停止されているため注意が必要です。

これらのライブラリを使うことによって Date オブジェクトにたいする不満は、ほぼ解消されると思います。

しかしながら、Moment.js のようにライブラリの開発が終わってしまった場合に、そのライブラリを利用していたプログラムを探し出して、リファクタリングするつらい経験をしてしまうと、使う機能だけ自分で作ってしまったほうが、いいんじゃない?ってなってしまうわけです。

では、1 つ目の問題点から確認していきます。

Date オブジェクトの比較

では、まず最初の問題点「日時の比較」ができない問題です。

コードの例で確認していきましょう。

function myFunction() {
  const date1 = new Date('2022/02/22');
  const date2 = new Date('2022/02/22');
  console.log(date1 === date2);  // false
  console.log(date1 == date2);  // false
}

このように、オブジェクトの特性を理解していないと目を疑うような結果になります。

このオブジェクト (とプリミティブ型) に対しての考察はこちらの記事がたいへん参考になります。

Qiita
JavaScriptに参照渡し/値渡しなど存在しない - Qiita tl;drJavaScriptに参照渡し/値渡しなど存在しない存在するのは変数に入る値の参照のみ変数に値を代入すると参照が切り替わるという様に考えれば不毛な議論を避けられるので...

この問題への対処法としては、特定のメソッドを使って比較する方法があります。

function myFunction() {
  const date1 = new Date('2022/02/22');
  const date2 = new Date('2022/02/22');
  console.log(date1.getTime() === date2.getTime());  // true
}

getTime メソッド以外にも toString メソッドなど、複数の選択肢があります

それでは、次の問題点「フォーマットするためのコードが長い」です。

Utilities クラスを利用したフォーマット

Date オブジェクトを、利用したい文字列型に変更するためには、Date オブジェクトのメソッドではなく、GAS の Utilities クラスにある formatDate メソッドを利用します。

以下で確認できます。

function myFunction() {
  const date = new Date('2022/02/22');
  const strDate = Utilities.formatDate(date, 'JST', 'yyyy/MM/dd');

  console.log(date);  // Tue Feb 22 2022 00:00:00 GMT+0900 (Japan Standard Time)
  console.log(strDate);  // 2022/02/22
}

Utilities クラスの formatDate メソッドの第 2 引数の timeZone には 'JST''Asia/Tokyo' のいずれかを選択することで日本標準時の値が取れます

Date オブジェクトのメソッド単体では、なかなか思うような処理ができず、以下の strDate1 のように、無理やり表示させる必要があります。

function myFunction() {

  const date = new Date('2022/02/22');
  const strDate1 = date.getFullYear() + '/' + (date.getMonth() + 1) + '/' + date.getDate();
  console.log(strDate1);  // 2022/2/22 NOTE: この値を取得したい

  const strDate2 = date.toDateString();
  console.log(strDate2);  // Tue Feb 22 2022
  
  const strDate3 = date.toLocaleDateString();
  console.log(strDate3);  // 2/22/2022

}

この書き方に比べれば formatDate メソッドはとても優秀です。

すこしクラス名が長くて、すこしメソッド名が長くて、すこし仮引数が多い点をのぞけば。

また、最後の問題点「月数が 0 – 11」が、ちょうどこの strDate1 のところで出現しています。

1 を加算することによって問題なくあつかえますが、たとえば「3 月」かどうかの判定をおこなうために date.getMonth() === 3 のように書いてしまい、エラーに悩まされた経験は、みなさんあると思います。

今回は、以上 3 点の問題点をクリアにするクラスを書いていきます。

クラス

実装するクラスのメンバー (プロパティとメソッド) について、かんたんに解説します。

メンバーの設定

メンバー種別メンバー名メンバーの内容
プロパティdateDate オブジェクト
メソッドisSame日時を比較するメソッド
メソッドgetMonth月数 (1 – 12) を返すメソッド
メソッドsetMonth月数 (1 – 12) を設定するメソッド
メソッドtoStringdate プロパティを指定の文字列にフォーマットするメソッド
静的メソッドformat指定の文字列にフォーマットする静的メソッド
Datetime クラスのメンバーの内容

今回は問題となった getMonth, setMonth のみ Date オブジェクトから手を加えて委譲しましたが、クラス内での利用や、クライアントでの利用状況に応じて getFullYear や getDate などを追加して、便利にご利用ください

クラス名は Datetime でいきます。

すごく悩んでたクラスの命名に一役買ってくれた ume ちゃん、ありがとう!

Datetime クラスのコード

'use strict'

class Datetime {

  /**
   * 日時に関するコンストラクタ
   * @constructor
   * @param {Date|string|number} param - Date オブジェクトでインスタンス生成可能な引数
   */
  constructor(param = new Date()) {
    /** @type {Date} */
    this.date = new Date(param);
  }

  /**
   * Date オブジェクトから委譲されたメソッド
   * NOTE: getMonth, setMonth の戻り値、仮引数は 0 - 11 を 1 - 12 に変更  
   */
  getMonth() { return this.date.getMonth() + 1; }
  setMonth(arg) { return this.date.setMonth(arg - 1); }

  /**
   * format 部分が同じものか比較するメソッド
   * @param {Date} date - 比較対象の Date オブジェクト
   * @param {string} format - 比較するフォーマット
   * @return {boolean} format 部分が同じかどうか
   */
  isSame(date, format = 'yyyy/MM/dd HH:mm:ss') {
    return Datetime.format(date, format) === Datetime.format(this.date, format);
  }

  /**
   * コンストラクタの date オブジェクトを指定のフォーマットで文字列化するメソッド
   * @param {string} format - フォーマットする形式
   * @return {string} フォーマットされた文字列型の日時
   */
  toString(format = 'yyyy/MM/dd HH:mm:ss') {
    const strDate = Datetime.format(this.date, format);
    return strDate;
  }

  /**
   * 指定のフォーマットで日時を文字列化する静的メソッド
   * @param {Date} d - Date オブジェクト 文字列型も可
   * @param {string} format - フォーマットする形式
   * @return {string} フォーマットされた文字列型の日時
   */
  static format(d = new Date(), format = 'yyyy/MM/dd HH:mm:ss') {
    const date = new Date(d);
    const strDate = Utilities.formatDate(date, 'JST', format);
    return strDate;
  }

}

今回は、手続き型でコーディングしていた部分と異なる点が多いので、もう少し詳しくメンバーについて説明していきます。

  • 唯一のプロパティ date プロパティは、Date オブジェクトが受けることができる仮引数のパターンすべてを受け、その値を new Date() した値を持ちます
  • getMonth, setMonth メソッドは、対応する値が 0 – 11 だったものを 1 – 12 に変更しました
  • isSame メソッドは、仮引数として受ける Date オブジェクトと第 2 引数のフォーマット形式部分のみを静的メソッド format を使って比較した結果を返します
    ※ 初期設定でミリ秒の比較はしません
  • toString メソッドは、静的メソッド format を使って、date プロパティを仮引数のフォーマット形式の文字列型に変更します
  • 静的メソッド format は第 1 引数の Date オブジェクトを第 2 引数のフォーマット形式の文字列型にして返します

今回 format のデフォルト引数は yyyy/MM/dd HH:mm:ss に設定してありますが、プログラム内で頻出するフォーマットに変更すると、さらにクラスを便利に利用できます

では、このクラスを実際に使ったコード例です。

function myFunction() {

  const dt = new Datetime('2022/02/22');
  console.log(dt);  //	{ date: Tue Feb 22 2022 00:00:00 GMT+0900 (Japan Standard Time) }

  console.log(dt.getMonth());  // 2

  dt.setMonth(5);
  console.log(dt.toString());  // 2022/05/22 00:00:00

  const date1 = new Date('2022/05/22');
  console.log(dt.isSame(date1));  // true

  console.log(Datetime.format(date1, 'yyyy/MM/dd'));  // 2022/05/22

  const date2 = new Date('2022/02/22');
  console.log(dt.isSame(date2));  // false

  console.log(dt.isSame(date2, 'yyyy'))  // true NOTE: 年 (4 桁) 部分を比較

}

今回問題点としてあげた 3 点は、すべてクリアになりました。

GitHub リンク

GitHub
GitHub - FrontWorks-Inc/blog_gas-create-datetime-class: create repository create repository. Contribute to FrontWorks-Inc/blog_gas-create-datetime-class development by creating an account on GitHub.

まとめ

さて、今回の記事はいかがでしたでしょうか。

とりまわしにコツのいる Date オブジェクトを独自クラスのプロパティに持たせることによって、必要なメソッドのみ Date オブジェクトから引き継ぎ、足りないメソッドをくわえることで、とても便利な Datetime オブジェクトが完成しました。

独自クラスのメリットが少しでも伝われば、嬉しいです。

また、弊社のコーディング ガイドラインでは 1 クラス 1 gs ファイルとしているので「あ、Date オブジェクト使うから、このクラス持ってこよう」くらいの軽い感じで、クラスを使いまわします。

今回は書かれていないメリットもあわせて以下の記事で読んでいただけると幸いです。

今後の記事では Google Workspace services のクラスについても、便利な独自クラスの利用例を紹介していければと思います。

gas-create-datetime-class_featured-image

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

株式会社フロント・ワークス代表取締役の etau です 🤓
へーしゃは「ノンプロ協会」に、個人では「ノンプロ研」所属しています。
趣味は「マンガ」「料理 (特にスパイス カレー)」「お酒」「コーヒー」「コーチング」「マネジメント」です。

目次