こんにちは、2022年の4月に新卒で入社してから5年目に突入した、茶谷です🍵
はじめに
弊社では、外部の勤怠システムに登録された「翌日の出社・リモートワーク・有休などの勤務予定」を、チャットに通知するBotを運用しています。
このBotは、私が1年目の春に開発した社内システムで、GAS(Google Apps Script)で動いています。
現在も、要望対応やリファクタリングを重ねながら運用しています。
不具合の発生
弊社冬季休業中、Botの通知が正しく動かない事がありました。
- 2025年12月30日は休業日なのでBotの通知もお休みのはずだが、明けの2026年1月5日の予定が通知されてしまった
すぐに不具合調査・対応できない状況だったので、冬季休業中は送信処理を停止させ、休暇明けに調査と修正を行うこととなりました。
原因の究明
2025年12月30日は確かに公休日としてシステムに登録されていましたが、
2026年1月5日の予定が通知されてしまいました。
どうしてかなと思い、デバッグしていると、2025年12月30日をフォーマットした結果「2026年12月30日」となっていることがわかりました。
当時、GASでは以下のように日付をフォーマットしていました。
|
1 |
var dateF = Utilities.formatDate(date,"Asia/Tokyo","YYYY-MM-dd"); |
GAS の Utilities.formatDate() は、
Java SE の SimpleDateFormat クラスの仕様に従って日付を書式設定します。
この仕様はGASの公式ドキュメントに記載されています。
仕様によると、
- y は 暦年(calendar year)
- Y は 週年(week-based year)
を表します。
週年(week-based year)とは
週年とは、「その日付が属する週」を基準にした年のことです。
ISO 8601 の週番号ルールでは、
- 週は月曜日始まり
- 年の最初の週は「その年の1月4日を含む週」
と定義されています。
※以降、この記事中での「週年」はISO 8601のルール基準の週年という前提で進めます
このため、年末の日付(12月29日〜31日頃)が
翌年の第1週に含まれる場合、
週年(Y)としては「翌年」と判定されます。
| 日付 | 曜日 | 暦年 (y) | 週年 (Y) |
|---|---|---|---|
| 2025/12/28 | 日 | 2025 | 2025 |
| 2025/12/29 | 月 | 2025 | 2026 |
| 2025/12/30 | 火 | 2025 | 2026 |
今回のBotは、12月30日に「翌営業日の予定」を取得しようとした際、プログラム内部で日付が「2026年12月30日」と解釈されてしまい、判定が狂ってしまったのが原因でした。
ちなみに...
PHPではどうなるのか
PHPでは「Y」と「y」どちらも暦年で、表示桁数に違いがあるのみになります。
| 日付 | 曜日 | 2桁表示 (y) | 4桁表示 (Y) |
|---|---|---|---|
| 2025/12/28 | 日 | 25 | 2025 |
| 2025/12/29 | 月 | 25 | 2025 |
| 2025/12/30 | 火 | 25 | 2025 |
もし週年でフォーマットしたい場合は、「o(小文字のオー)」を使います。
| 日付 | 曜日 | 暦年(Y) | 週年(o) |
|---|---|---|---|
| 2025/12/28 | 日 | 2025 | 2025 |
| 2025/12/29 | 月 | 2025 | 2026 |
| 2025/12/30 | 火 | 2025 | 2026 |
Javascriptの場合
JavascriptのgetFullYear()で取得できる年は暦年になります。
| 日付 | 曜日 | getFullYear() |
|---|---|---|
| 2025/12/28 | 日 | 2025 |
| 2025/12/29 | 月 | 2025 |
| 2025/12/30 | 火 | 2025 |
Day.jsのformat()では、「Y」は暦年、「G」は週年になるようです。
| 日付 | 曜日 | 暦年 (YYYY) | 週年 (GGGG) |
|---|---|---|---|
| 2025/12/28 | 日 | 2025 | 2025 |
| 2025/12/29 | 月 | 2025 | 2026 |
| 2025/12/30 | 火 | 2025 | 2026 |
参考:
https://day.js.org/docs/en/display/format#list-of-all-available-formats
https://day.js.org/docs/en/plugin/advanced-format
まとめ
一見同じに見える YYYY と yyyy ですが、言語によって意味が大きく異なるため注意が必要です。
特に年末付近の処理では思わぬ不具合につながるため、意識して使い分けることが重要ですね。


