起こった問題
const date1 = new Date('0001-12-17 03:24:00');
// > Thu Jan 12 2017 03:24:00 GMT+0900 (日本標準時)
const date2 = new Date('0011-12-17 03:24:00');
// > Sun Nov 12 2017 03:24:00 GMT+0900 (日本標準時)
date1
で、期待しているのは1年12月17日
です。
ん?? 2017年1月12日
。
1桁or2桁の年、つまり、1~99年の場合にバグります
しかし、年が100年以上の場合、再現できません
const date3 = new Date('0111-12-17 03:24:00');
// > Thu Dec 17 0111 03:24:00 GMT+0918 (日本標準時)
const date4 = new Date('1111-12-17 03:24:00');
// > Sun Dec 17 1111 03:24:00 GMT+0918 (日本標準時)
(@im44794さん からのご指摘より修正:2022/08/27)
バグというより、文字列指定での正常動作は保証されていないだけです。
(ご指摘より)
Note: 注: Date コンストラクター (および同じように動作する Date.parse()) を使用した日付文字列の解析は、ブラウザーによって違いや矛盾があるため、使用を避けることを強くお勧めします。。
・RFC 2822 書式の文字列の対応は慣習的に行われているだけです。
・ISO 8601 形式の対応は、日付のみの文字列 (例えば 1970-01-01) が地方時ではなく UTC として扱われる点が異なります。
mdn
今回私が実装していたように、文字列指定するとブラウザごとにECMAスクリプトのバージョンの差異によって正常に動作しない場合があるみたいです
対応としては、ブラウザごとの差異をなくすためにも、異なる書式に対応したライブラリを使用することを推奨する記載がmdn:Date.parse()
の方にあります
(mdn:Date.parse())
どのように修正するかの結論
const date = new Date('0001-12-17T03:24:00');
// > Mon Dec 17 0001 03:24:00 GMT+0918 (日本標準時)
let today = new Date()
let birthday = new Date('December 17, 1995 03:24:00')
let birthday = new Date('1995-12-17T03:24:00')
let birthday = new Date(1995, 11, 17) // the month is 0-indexed
let birthday = new Date(1995, 11, 17, 3, 24, 0)
mdnにも記載ありますが、年月日と時間の間のT
が漏れていました
(@551361sさん のご指摘より以下追記:2022/08/27)
日本では年-月-日の順で記述するのが普通なので上記結果は違和感があるかもしれませんが、国によっては月-日-年の順だったりもするので、どちらとも解釈できてしまうケースで意図した結果とならないことがあるのは仕方のないことです。
なので、ISO8601形式であれば日付部分は年月日の順に指定することが国際的に定められているので、年が0099以下であっても上手くいくわけです。
(@551361sさん のご指摘より)
'0001-12-17T03:24:00'
は、ISO8601に準拠した形式であるため、パースが可能です
以下のISO8601の拡張形式に準拠したものも。
const date1 = new Date('0001-09-27');
// > Thu Sep 27 0001 09:18:59 GMT+0918 (日本標準時)
上記の対応でも、環境によってはバグ?
開発環境では、日付のパースが正常にできていたのですが、リリース環境ですとパースエラー。。。
なので、日付の処理は素直にライブラリで対応しましょう
今(2022/8 時点)だと、datefnsですかね
datefnsのparseを使用して対応
const result = parse('0001-12-17 03:24:00', 'yyyy-MM-dd HH:mm:ss', new Date())
// > Mon Dec 17 0001 03:24:00 GMT+0918 (日本標準時)
動作確認してませんが期待した結果が得られるはずです