【0からGASを学ぶ】dayjs ライブラリを用いて、GASの日付操作で楽をしよう！

# はじめに
本シリーズでは、GASの始め方や便利な使い方、ビジネス活用まで幅広く解説します。シリーズをひと通り読んでいただければ、あなたもきっとGASマスターになれるはずです。

# シリーズの対象者
* そもそもGASってなんだか**わからない**方
* GASを学びたいけど**何から始めればいいか**わからない方
* GASはわかり始めたけど、**もっと活用ができないか**と模索している方
* とにかく**Googleが好き！** という方

# 前回記事
https://qiita.com/gas-suke/items/e036bb8518386139b00e

# dayjsライブラリを使いこなす
では早速始めていきましょう。【0からGASを学ぶ】シリーズの第13回は「dayjs ライブラリを用いて、GASの日付操作で楽をしよう！」です。前回、Googleフォームを用いた自動化の中で、`dayjs`ライブラリを初めて登場させました。今後、**このライブラリはヘビーに登場**しますので、**様々な日付操作**をお伝えしておきたいと思います。

## 今回やること
1. 現在日時および指定日時オブジェクトの生成
1. 指定フォーマットの出力
1. 各プロパティの取得、設定
1. 日時の加算、減算
1. 日時同士の差分を取得
1. 日時同士の比較
1. ちょっと便利な使い方

:::note warn
dayjsに関しては、以下ページにて各種使い方がまとまっていますが、GAS版のdayjsでは**すべてのメソッドが使用できるわけではない**ので、注意しましょう。代表的なものだと`IsSameOrAfter`などがあげられます。これは、正確には`IsSameOrAfter`は**dayjsのpluginメソッドであるため**です。
[Day.jsのAPI説明ページはこちらから](https://day.js.org/docs/en/installation/installation)
:::

## プログラム開始
### GASエディタを開く
今回はdayjsライブラリを使い倒すことだけを目的としているため、**スタンドアロン型**でGASを記述していきます。[こちら](https://qiita.com/gas-suke/items/5cf7bd4c6c3f15a25838#%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%89%E3%82%A2%E3%83%AD%E3%83%B3%E5%9E%8B)を参考にGASエディタを起動してください。では、どんどんいきますよ、ついてきてください。

### STEP.0　dayjsライブラリを追加する
<table>
  <tr>
    <th>№</td>
    <th>手順</td>
    <th>イメージ</td>
  </tr>
  <tr>
    <td>1</td>
    <td>GASエディタの左メニューより「ライブラリ」横の「＋」をクリックします。</td>
    <td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/f57ab39c-abcc-088b-8f55-b30422adcb63.png" width="400"></td>
  </tr>
  <tr>
    <td>2</td>
    <td>表示されたダイアログ上のスクリプトID入力欄に以下IDを入力し、「検索」をクリックします。<br/><B>1ShsRhHc8tgPy5wGOzUvgEhOedJUQD53m-gd8lG2MOgs-dXC_aCZn9lFB</B></td>
    <td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/e42ea7e9-088b-85e7-0ce1-27332fa81331.png" width="500"></td>
  </tr>
  <tr>
    <td>3</td>
    <td>検索結果が表示されたら、特段変更することなく「追加」をクリックします。</td>
    <td></td>
  </tr>
</table>

:::note info
上記ダイアログのID欄にデフォルトは「dayjs」と表示されていますが、ここを変更すると、プロジェクト内で**dayjsライブラリにアクセスするための文字列を変更できます**。が、通常あまりやりません。
:::


### STEP.1　現在日時および指定日時オブジェクトの生成
```javascript:Qiita013.gs
function Qiita013() {
  // 現在日時を取得する
  let now = dayjs.dayjs();

  // 指定日時を取得する
  let assignDate = dayjs.dayjs('2010/4/1 13:55:12');

  console.log(now);
  console.log(assignDate);
}
```

```:実行結果
17:23:17	お知らせ	実行開始
17:23:18	情報	{ '$L': 'en',
  '$d': Mon Dec 04 2023 17:23:18 GMT+0900 (Japan Standard Time),
  '$x': {},
  '$y': 2023,
  '$M': 11,
  '$D': 4,
  '$W': 1,
  '$H': 17,
  '$m': 23,
  '$s': 18,
  '$ms': 175 }
17:23:18	情報	{ '$L': 'en',
  '$d': Thu Apr 01 2010 13:55:12 GMT+0900 (Japan Standard Time),
  '$x': {},
  '$y': 2010,
  '$M': 3,
  '$D': 1,
  '$W': 4,
  '$H': 13,
  '$m': 55,
  '$s': 12,
  '$ms': 0 }
17:23:17	お知らせ	実行完
```
簡単ですね。ちなみに指定日付の場合は、`/`ではなく`-`とした場合でも問題なくオブジェクトを生成できます。
```javascript
let assignDate = dayjs.dayjs('2010-4-1 13:55:12');
```

### STEP.2　指定フォーマットの出力
次に、生成したオブジェクトをフォーマットを指定して、文字列として取得してみましょう。

**の前に！！！** STEP.1でお気づきの方もいると思いますが、実行結果を見ると
```
'$L': 'en'
```
となっています。これは**ロケールが英語**となっていることを意味し、このままだと**文字列を出力した際に曜日等が英語**になってしまいます。そこでこれはお約束として、dayjsで日付操作を行う場合は、**一番最初にロケール設定を日本**に変更しましょう。といっても以下の1行を書くだけです。
```javascript
dayjs.dayjs.locale('ja');
```

:::note info
タイムゾーンは`GMT+0900 (Japan Standard Time)`となっているため、日付操作のみを行う場合は**特段ロケールを変更する必要はありません**が、間違いが起こらないように**必ず設定**するようにしましょう。
:::

それでは、気を取り直して、指定フォーマットでの出力を試したいと思います。
```javascript:Qiita013.gs
function Qiita013() {
  dayjs.dayjs.locale('ja');
  // 現在日時を取得する
  let now = dayjs.dayjs();

  console.log(now.format('YYYY-MM-DD HH:mm:ss'));
  
  // 年
  console.log(now.format('YY'));
  console.log(now.format('YYYY'));

  // 曜日
  console.log(now.format('d'));
  console.log(now.format('dd'));
  console.log(now.format('dddd'));
}
```
```:実行結果
17:30:32	お知らせ	実行開始
17:30:33	情報	2023-12-04 17:30:33
17:30:33	情報	23
17:30:33	情報	2023
17:30:33	情報	1
17:30:33	情報	月
17:30:33	情報	月曜日
17:30:32	お知らせ	実行完了
```
生成した`dayjs`オブジェクトに対して、`format`メソッドを用いて**パラメタを指定すれば様々な情報を取得**することができます。

| パラメタ | 出力例 | 説明 |
|:-:|:--|:--|
| YY | 23 | 2桁年表記 |
| YYYY | 2023 | 4桁年表記 |
| M | 1, 12 | 1桁月表記（2桁のものはもちろん2桁） |
| MM | 01, 12 | 2桁月表記 |
| MMMM | 1月, 12月 | 日本語月表記 |
| D | 1, 31 | 1桁日表記 |
| DD | 01, 31 | 2桁日表記 |
| d | 0, 6 | 数値曜日表記（日曜日を0としてインクリメント） |
| dd | 月 | 日本語曜日表記（短縮） |
| dddd | 月曜日 | 日本語曜日表記 |
| H | 0, 23 | 1桁時間表記（24時間制） |
| HH | 00, 23 | 2桁時間表記（24時間制） |
| h | 0, 12 | 1桁時間表記（12時間制） |
| hh | 00, 12 | 2桁時間表記（12時間制） |
| m | 0, 59 | 1桁分表記 |
| mm | 00, 59 | 2桁分表記 |
| s | 0, 59 | 1桁秒表記 |
| ss | 00, 59 | 2桁秒表記 |
| SSS | 000, 999 | ミリ秒表記 |
| Z | +09:00 | 協定世界時 (UTC) との差分 |
| ZZ | +0900 | 協定世界時 (UTC) との差分 |
| A または a | 午前, 午後 | AM/PMの表記 |

:::note info
ロケール設定が`en`の場合は、***MMM***や***ddd***も意味のあるものとなりますが、`ja`の場合は他のパラメタ設定と同一であるため、ここでは省略しています。
:::

### STEP.3　各プロパティの取得、設定
出力値としては`format`メソッドに似ていますが、各プロパティも取得してみましょう。
```javascript:Qiita013.gs
function Qiita013() {
  dayjs.dayjs.locale('ja');
  // 現在日時を取得する
  let now = dayjs.dayjs();

  console.log(now.year());
  console.log(now.month());

  now = now.year(2021);
  console.log(now.year());
}
```
```:実行結果
17:32:47	お知らせ	実行開始
17:32:47	情報	2023
17:32:47	情報	11
17:32:47	情報	2021
17:32:47	お知らせ	実行完了
```
そりゃそうだろって結果ですが、dayjsでは各プロパティの取得も設定も**非常に簡単に、直感的に**できるのが魅力です。

::: note warn
直感的で明瞭ですが、プロパティの取得・設定時には**ひとつ注意点**があります。

```JavaScript
now.day()
now.date()
```
なんとなく、`day`と書くと日付が取得できそうですがこれは**曜日（日曜日を0としてインクリメント）を取得**します。**日付は`date`** なのでお間違えの無いよう。
:::

### STEP.4　日時の加算、減算
次は、加算と減算です。それぞれ`add`および`subtract`、そして**各種パラメタ（y, M, d等）を用いる**ことで加算・減算が可能です。それではプログラムを見てみましょう。
```javascript:Qiita013.gs
function Qiita013() {
  dayjs.dayjs.locale('ja');
  // 現在日時を取得する
  let now = dayjs.dayjs();
  console.log(now.format('YYYY-MM-DD HH:mm:ss.SSS'));

  // 加算する
  console.log('1年加算　　：' + now.add(1, 'y').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1月加算　　：' + now.add(1, 'M').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1週加算　　：' + now.add(1, 'w').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1日加算　　：' + now.add(1, 'd').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1時間加算　：' + now.add(1, 'h').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1分加算　　：' + now.add(1, 'm').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1秒加算　　：' + now.add(1, 's').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1ミリ秒加算：' + now.add(1, 'ms').format('YYYY-MM-DD HH:mm:ss.SSS'));

  // 減算する
  console.log('1年減算　　：' + now.subtract(1, 'y').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1月減算　　：' + now.subtract(1, 'M').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1週減算　　：' + now.subtract(1, 'w').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1日減算　　：' + now.subtract(1, 'd').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1時間減算　：' + now.subtract(1, 'h').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1分減算　　：' + now.subtract(1, 'm').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1秒減算　　：' + now.subtract(1, 's').format('YYYY-MM-DD HH:mm:ss.SSS'));
  console.log('1ミリ秒減算：' + now.subtract(1, 'ms').format('YYYY-MM-DD HH:mm:ss.SSS'));
}
```
```:実行結果
17:39:31	お知らせ	実行開始
17:39:32	情報	2023-12-04 17:39:32.359
17:39:32	情報	1年加算　　：2024-12-04 17:39:32.359
17:39:32	情報	1月加算　　：2024-01-04 17:39:32.359
17:39:32	情報	1週加算　　：2023-12-11 17:39:32.359
17:39:32	情報	1日加算　　：2023-12-05 17:39:32.359
17:39:32	情報	1時間加算　：2023-12-04 18:39:32.359
17:39:32	情報	1分加算　　：2023-12-04 17:40:32.359
17:39:32	情報	1秒加算　　：2023-12-04 17:39:33.359
17:39:32	情報	1ミリ秒加算：2023-12-04 17:39:32.360
17:39:32	情報	1年減算　　：2022-12-04 17:39:32.359
17:39:32	情報	1月減算　　：2023-11-04 17:39:32.359
17:39:32	情報	1週減算　　：2023-11-27 17:39:32.359
17:39:32	情報	1日減算　　：2023-12-03 17:39:32.359
17:39:32	情報	1時間減算　：2023-12-04 17:39:32.359
17:39:32	情報	1分減算　　：2023-12-04 17:38:32.359
17:39:32	情報	1秒減算　　：2023-12-04 17:39:31.359
17:39:32	情報	1ミリ秒減算：2023-12-04 17:39:32.358
17:39:32	お知らせ	実行完了
```

:::note info
明確に`加算：add`メソッドと`減算：subtract`メソッドがありますが、`add`の引数に**マイナスの数値を渡せば減算**を行うことはできます。
:::

これ以降に、パラメタはヘビーに登場しますので、一覧で示しておきます。といっても、そりゃそうだろってパラメタです。

| パラメタ | 短縮表記 | 説明 |
|:-:|:-:|:--|
| year | y | 年 |
| month | M | 月 |
| week | w | 週 |
| day | d | 日 |
| hour | h | 時間 |
| minute | m | 分 |
| second | s | 秒 |
| millisecond | ms | ミリ秒 |

### STEP.5 日時同士の差分を取得
次は、差分の取得です。これには`diff`メソッドを用いますが、**少々注意が必要なメソッド**となりますので、扱い方には気を付けましょう。何が注意なのか、これはプログラムから見ていきたいと思います。
```javascript:Qiita013.gs
function Qiita013() {
  dayjs.dayjs.locale('ja');
  // 基準日時を生成する
  let assignDateFrom = dayjs.dayjs('2023/4/1 13:00:00');
  
  // 比較日時を生成する
  let assignDateTo = dayjs.dayjs('2023/6/1 12:59:59');
  
  console.log(assignDateTo.diff(assignDateFrom, 'y'));
  console.log(assignDateTo.diff(assignDateFrom, 'M'));
  console.log(assignDateTo.diff(assignDateFrom, 'd'));
}
```
```:実行結果
17:46:14	お知らせ	実行開始
17:46:15	情報	0
17:46:15	情報	1
17:46:15	情報	60
17:46:15	お知らせ	実行完了
```
上記プログラムではあえて、基準日時の時刻に対して、比較日時の時刻を**1秒前**としました。このようにした場合、`2023/4/1`と`2023/6/1`で見れば**2ヶ月の差分**がありますが、厳密にミリ秒単位で評価をすると2ヶ月になりきっていないため、**1ヶ月となります**。そのため、diffメソッドを用いる際は、**ミリ秒単位で評価している**ということに注意しましょう。

:::note info
あくまでも**日付だけで評価をしたい**とか評価する対象が明確な場合には、`dayjs`の`startOf`や`endOf`メソッドを併せて用いるとよいです。例えば先ほどのような、基準日時と比較日時であろうと、
```javascript
assignDateTo.startOf('day').diff(assignDateFrom.startOf('day'), 'M');
```
このようにすれば、互いの`00:00:00`時点の評価となり、**2ヶ月の差分が取得**できます。
:::

### STEP.6 日時同士の比較
次は、比較です。これには`isBefore`、`isSame`、`isAfter`の3つのメソッドを用います。まずは、プログラムから見ていきたいと思います。
```javascript:Qiita013.gs
function Qiita013() {
  dayjs.dayjs.locale('ja');
  // 基準日時を生成する
  let assignDate = dayjs.dayjs('2023/4/1 13:00:00');
  
  // 比較日時_前を生成する
  let assignDate_Bef = dayjs.dayjs('2023/2/1 13:00:00');
  
  // 比較日時_後を生成する
  let assignDate_Aft = dayjs.dayjs('2023/6/1 13:00:00');
  
  console.log(assignDate_Bef.isBefore(assignDate));
  console.log(assignDate_Aft.isBefore(assignDate));
  
  console.log(assignDate_Bef.isSame(assignDate));
  console.log(assignDate_Aft.isSame(assignDate));
  console.log(assignDate_Bef.isSame(assignDate, 'y'));
  console.log(assignDate_Aft.isSame(assignDate, 'y'));
  
  console.log(assignDate_Bef.isAfter(assignDate));
  console.log(assignDate_Aft.isAfter(assignDate));
}
```
```:実行結果
17:55:41	お知らせ	実行開始
17:55:41	情報	true
17:55:41	情報	false
17:55:41	情報	false
17:55:41	情報	false
17:55:41	情報	true
17:55:41	情報	true
17:55:41	情報	false
17:55:41	情報	true
17:55:41	お知らせ	実行完了
```
比較メソッドも`diff`と同じくですが、明確に評価対象をパラメタ指定することで比較結果を変化させることができます。

### STEP.7 ちょっと便利な使い方
日付操作は、プログラムの中で結構頻繁に行われるかと思います。これまで紹介した使い方以外に例えば、**月初**や**月末**、**翌月末**、**年始**、**年末**、**年度末**などを取得したい時があるかと思います。そんな時は、以下を参考にしてみてください。
#### 月初
```javascript
let now = dayjs.dayjs();
console.log(now.startOf('M').format('YYYY-MM-DD HH:mm:ss'));
```
#### 月末
```javascript
let now = dayjs.dayjs();
console.log(now.endOf('M').format('YYYY-MM-DD HH:mm:ss'));
```
#### 翌月末
```javascript
let now = dayjs.dayjs();
console.log(now.add(1, 'M').endOf('M').format('YYYY-MM-DD HH:mm:ss'));
```
#### 年始
```javascript
let now = dayjs.dayjs();
console.log(now.startOf('y').format('YYYY-MM-DD HH:mm:ss'));
```
#### 年末
```javascript
let now = dayjs.dayjs();
console.log(now.endOf('y').format('YYYY-MM-DD HH:mm:ss'));
```
#### 年度末
```javascript
let now = dayjs.dayjs();
if (now.month() >= 3) {
  console.log(now.add(1, 'y')
                 .month(2)
                 .endOf('M').format('YYYY-MM-DD HH:mm:ss'));
} else {
  console.log(now.month(2)
                 .endOf('M').format('YYYY-MM-DD HH:mm:ss'));
}
```
こちらだけ簡単に解説すると、現在日時が4/1～12/31であれば**年度末は翌年**となるため、**現在年に1を加算させたのちに、3月の末日を取得**します。


### 
# おわりに
お疲れ様でした。
第13回は「dayjs ライブラリを用いて、GASの日付操作で楽をしよう！」ということで、GASで使用することのできる**dayjsライブラリの代表的なメソッドや使い方**をひたすらお伝えしました。このライブラリは今後はもちろんですが、これまでの12回の中でも**これを使えばもっと楽に記述できた箇所も往々にしてあります**。このようにGASはライブラリを追加することで、**プログラムをより簡潔に記述することも可能**です。引き続き、GASを楽しんでいきましょう！！
記事を読んで、「良いな」や「今後に期待できる！」と感じて頂けたら**いいね**や**フォロー**、**コメント**いただけると幸いです。それではまた次回をお楽しみに！

## ブログでより詳しく解説しています！
以下画像をクリックしてブログにアクセス！！
<a href="https://gas-4u.com/gas12/" target="_blank"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/29881f6f-db28-8e51-a314-e4d6bbe0cf91.png" width="600"/></a>