「2026-02-30」を渡したら、PHP と JavaScript だけが黙って3月2日にした ― その書き方、本当に通る?①

Go
B!

存在しない日付「2026-02-30」を、10言語のいちばん普通の日付の読み方に渡しました。8言語は「日付が正しくありません」と言い、PHP と JavaScript の2言語だけが、何も言わずに 2026年3月2日 として計算を続けました。

何をしたか

CODE Polyglot の入門 第8回 は、日付と日数を受け取って「その日の曜日」「◯日後の日付」「その月の最終日」を出すプログラムです。正解表は先に決めてあり、存在しない日付のときは「日付が正しくありません」と出すのが正解です。

各言語で、初心者が最初に習う読み方をそのまま使った版(つまずきやすい書き方)を用意し、毎朝の検証と同じ Linux の環境で動かしました。

言語使った読み方2026-02-30 を渡すと
Pythondatetime.strptimeエラー → 「日付が正しくありません」
Gotime.Parseエラー → 同上
RubyDate.parseエラー → 同上
Java・KotlinLocalDate.parseエラー → 同上
C#DateTime.Parseエラー → 同上
SwiftDateFormatternil → 同上
Rust(標準に日付が無いので、年月日の整数で計算)同上
PHPnew DateTimeエラーにならず、2026-03-02 として続ける
JavaScriptnew Dateエラーにならず、2026-03-02 として続ける

PHP が実際に出した答えはこうです。

2026-03-02 は月曜日です
1日後は 2026-03-03(火曜日)
この月の最終日は 2026-03-31

2月30日を「2月の30日目」=「2月28日の2日後」と読んで、3月2日に繰り越しています。止まらないので、エラーの処理(try / catch)を書いていても素通りします。

どう直したか

読み取る前に「その日が存在するか」を確かめます。PHP には checkdate があります。

$parts = explode("-", $argv[1]);
if (count($parts) !== 3 || !checkdate((int)$parts[1], (int)$parts[2], (int)$parts[0])) {
    echo "日付が正しくありません\n";
    exit;
}

JavaScript には checkdate に当たるものが無いので、作った日付の年・月・日が入力どおりかを比べます。

const d = new Date(Date.UTC(y, m - 1, day));
if (d.getUTCFullYear() !== y || d.getUTCMonth() !== m - 1 || d.getUTCDate() !== day) {
  console.log("日付が正しくありません");
  process.exit();
}

まとめ

  • 「読めなかったらエラーになるはず」は、言語と関数によっては成り立たない
  • 問い合わせフォームの生年月日や予約日など、人が入力した日付は、読んだあとに「入力どおりか」を確かめる
  • 10言語の全プログラムと、つまずきの表は 入門 第8回 にあります。毎朝、実際に動かして確かめています
連載「その書き方、本当に通る?」(全4回)
  1. 第1回:「2026-02-30」を渡したら、PHP と JavaScript だけが黙って3月2日にした(この記事)
  2. 第2回:JavaScript で「月の最終日」を出したら、日本では毎回1日前になった
  3. 第3回:C# の Normalize(FormKC) が、Docker の中では何もしなかった
  4. 第4回:辞書の「取り出す順番」を10言語で20回ずつ試したら、5通りの性格に分かれた
B!
← 一覧へ戻る