JavaScriptで日付が正しいかチェックする


# JavaScriptで、YYYY/MM/DD形式の日付が正しいかチェックする

* [記事へのコメントで、より良いコード](https://qiita.com/JCXNAUTNKH/items/7b03234738d4f36dd823#comment-4961583b7b5837242ad6)をいただいたのでそちらをご参照ください。

* 更新：記事へのコメントに倣い、 toJSON と split('T') を使うように修正しました。


JavaScriptで、YYYY/MM/DD形式の日付が正しいかチェックするのが意外と難しかった。
探してみた範囲では、2月30日を正しい日付と判定してしまうものしか見つからなかったので、作ったものと、JEST用のテストコードをここに置きます.



``` JavaScript
/**
 * 文字列が、YYYY/MM/DD 形式の正しい日付か確認する
 * @param {*} str_date 
 * @returns 
 */
const isValidDate = (str_date) => {
    //Dateは、日付のみの書式をUTCとして解釈する。toJSONやtoISOStringは常にUTCで返す。
    const str_iso = new Date(str_date.replace(/\//g, '-')).toJSON();

    //new Date() が引数を解釈できなかったらfalseを返す。
    if (!str_iso) return false;

    // 年/月/日T時:分:秒Z の文字列のうち、Tより前の部分を取得
    const date_iso = str_iso.replace(/\-/g, '/').split('T')[0];

    //引数の文字列が正しくない日付（例：2025/02/30）だったら、
    //date_isoは違う文字列（例：2025/03/01）になる。
    return (str_date === date_iso);
};


window.isValidDate = isValidDate;
if (typeof module !== "undefined" && module.exports) {
    module.exports = { isValidDate }; //JEST用
}
```

# JESTでテスト

JESTで実行するテストを書いた。

``` JavaScript
const { isValidDate } = require("./isValidDate");

test(
    "2月30日は正しい日付ではない", () => {
        expect(isValidDate('2025/02/30')).toBe(false);
    }
);
test(
    "全く日付では無いものは、偽と判定する", () => {
        expect(isValidDate('aaa')).toBe(false);
    }
);
test(
    "４桁/2桁/2桁ではないものは偽と判定する", () => {
        expect(isValidDate('1111/22/33/4')).toBe(false);
    }
);
test(
    "月も日にちも一桁になる日付", () => {
        expect(isValidDate('2025/01/01')).toBe(true);
    }
);
test(
    "8月末", () => {
        expect(isValidDate('2025/08/31')).toBe(true);
    }
);
test(
    "月も日にちも一桁になる日付", () => {
        expect(isValidDate('2025/09/01')).toBe(true);
    }
);
test(
    "月と日が正しくない", () => {
        expect(isValidDate('2222/33/44')).toBe(false);
    }
);
test(
    "2100年は、閏年ではない", () => {
        expect(isValidDate('2100/02/29')).toBe(false);
    }
);
test(
    "2020年は、閏年である", () => {
        expect(isValidDate('2004/02/29')).toBe(true);
    }
);
test(
    "2025年は、閏年ではない", () => {
        expect(isValidDate('2025/02/29')).toBe(false);
    }
);
test(
    "4月31日は無い", () => {
        expect(isValidDate('2025/04/31')).toBe(false);
    }
);
test(
    "13月は無い", () => {
        expect(isValidDate('2025/13/01')).toBe(false);
    }
);
test(
    "日付が正しい", () => {
        expect(isValidDate('2222/12/31')).toBe(true);
    }
);
```

# JESTのインストールとテスト実行

この記事冒頭のコードをファイル名`isValidDate.js`、テストコードを `isValid.spec.js` として保存する。
保存したフォルダで以下を実行する。

参考: https://jestjs.io/ja/docs/getting-started


```
$ npm init
$ npm install --save-dev jest
```
`package.json`の、"scripts:"{"test": ...  を、"jest"に書き換える。
``` JSON
  "scripts": {
    "test": "jest"
  }
```
テストを実行する。
```
$ npm test
```

# ブラウザで動かしてみる

``` html
<!DOCTYPE html>
<html>

<head>
    <title>isValidDate動作例</title>
    <script src="./isValidDate.js"></script>
</head>

<body>
    <input onchange="validateDate(this)" placeholder="YYYY/MM/DD形式の日付">
    <span id="result"></span>
    <script>
        function validateDate(obj) {
            const is_valid = isValidDate(obj.value);
            const elem = document.getElementById("result");
            if (is_valid) {
                elem.innerText = "YYYY/MM/DD形式の日付";
            } else {
                elem.innerText = "YYYY/MM/DD形式の日付ではない";
            }
        }
    </script>
</body>

</html>
```