0

投稿日

ISOフォーマット文字列の日付が存在するかチェックする

行いたいこと

  • 2/31のような存在しない日付が入力されたときに日付の存在チェック
  • 入力値はISOフォーマットの文字列

弊害となっていること

  • Number.isNaN(new Date(isoString).getTime())は2/31のような日付の場合にチェック漏れしてしまう。
  • ISOフォーマットには末尾にタイムゾーンを表す文字列があり、この文字列次第で日付の正規表現抽出し、new Date(iso)で作成したDateオブジェクトのgetDateで比較を行う処理に失敗する。

対処方法

  • チェック時のみタイムゾーンをZに置き換えて日付を比較する

サンプルコード

/**
 * ISOフォーマット文字列の検証
 * @param {*} isoString ISOフォーマット文字列
 * @returns 警告判定
 */
export const isoValidator = (isoString) => {
    // タイムゾーンを無視するため強制的に末尾をZに置き換える
    const enforceUtcIso = isoString.replace(/[+|-]\d{1,2}:\d{1,2}$/, "Z");
    // isoフォーマットが正常か判定する (例: 2023-01-01T01:02:03.444Z)
    const match = enforceUtcIso.match(
            /^(\d{4})-(\d{2})-(\d{2})T(0[0-9]|1[0-9]|2[0-3]):([0-5]\d):([0-5]\d)(.\d+Z|Z)$/
        );

    if (match == null || match.length < 8) {
        // isoフォーマットに不正確な部分がある場合
        return true;
    }

    const parsedDate = new Date(enforceUtcIso);
    if (Number.isNaN(parsedDate.getTime())) {
        // ISO文字列のパースに失敗した場合
        return true;
    }

    return (
        parsedDate.getUTCFullYear() !== parseInt(match[1], 10) ||
        (parsedDate.getUTCMonth() + 1) !== parseInt(match[2], 10) ||
        parsedDate.getUTCDate() !== parseInt(match[3], 10)
    );
};

新規登録して、もっと便利にQiitaを使ってみよう

  1. あなたにマッチした記事をお届けします
  2. 便利な情報をあとで効率的に読み返せます
ログインすると使える機能について

コメント

(編集済み)

こんな感じでどうでしょう。

const isoValidator = isoString => {
  const t = `${isoString}`.replace(/[+-]\d\d:\d\d$/, 'Z');
  return !/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?Z$/.test(t) ||
    new Date(t).toJSON()?.match(/\d+T/)[0] !== t.match(/\d+T/)[0];
};

ワンライナーで

const isoValidator = s => !/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?Z$/.test(s = `${s}`.replace(/[+-]\d\d:\d\d$/, 'Z')) || new Date(s).toJSON()?.match(/\d+T/)[0] !== s.match(/\d+T/)[0];
1
あなたもコメントしてみませんか :)
新規登録
すでにアカウントを持っている方はログイン
記事投稿キャンペーン開催中
RECOROKUを使ったナレッジ管理や情報共有のユースケースを投稿しよう!
~
はじめての記事を投稿
~
0