2026.04.14.火

GASでYYYYを使うと年がズレる罠にハマった話

技術

こんにちは、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では以下のように日付をフォーマットしていました。


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

まとめ

一見同じに見える YYYYyyyy ですが、言語によって意味が大きく異なるため注意が必要です。
特に年末付近の処理では思わぬ不具合につながるため、意識して使い分けることが重要ですね。

茶谷

茶谷

2022年4月に新卒で入社したサーモン大好き社員です。 プログラムを書くのが好きです。 2026年に入って猫を飼い始めました。 いえ、猫派ではありません、あくまでうちの子派です🐈️