JavaScript の Date の扱いが面倒という話。
個人的には
結局中身は UTC の unixtime ですよと言われれば、あーなるほどという感じ
かなと思うんだけど、一方で以下の部分がつらいなと思った。
- Date と言いつつ中身は Time で、Date を表現する方法がない
- new Date(YYYY, MM, DD) の MM が 0 origin
欲しいものがないならいったん作りましょうということでできたのでこれ。
/**
* @param {string} dateString YYYY-MM-DD
* @returns {Date}
*/
function parseDateWithLocalTZ (dateString) {
const d = new Date(dateString)
return new Date(d.getFullYear(), d.getMonth(), d.getDate())
}
普通に string で日付を与えて Date オブジェクトを作りたいんだけど、なんでこんなものが欲しかったのかというと、
- Date はローカルの TZ でしか Date オブジェクトを作れません ← 文字列を与える場合はそうとは限らない
- 文字列で Date を初期化する場合は実は挙動が分かれる
- 時刻まで書いている場合は、TZ 表記を省略するとローカルの TZ が採用される(ローカルTZ基準の挙動が正なら納得)
- 時刻を省略してしまうと UTC になる
1 は Node.js だと以下のような感じ。
> new Date('2023-08-01T00:00:00')
2023-07-31T15:00:00.000Z
この挙動は ISO 8601 とも合致しているはず。
2 も同様に実行してみると、
> new Date('2023-08-01')
2023-08-01T00:00:00.000Z
あれ? UTC として解釈されて返ってくる。たまたま「日付」の単位で処理を書きたかったので、お? となった。ここら辺の謎い挙動だけなんとかしてほしいなぁと思った。
上の関数を使うと
> parseDateWithLocalTZ('2023-08-01')
2023-07-31T15:00:00.000Z
で期待通り。
もう一つ加えるとしたら Invalid Date で、上のコードは Invalid Date の場合、そのままスルーで Invalid Date が返ってくるので、
JavaScript で Invalid Date を判定する
この辺のノウハウを活かしてなんとかするしかない。
Detecting an "invalid date" Date instance in JavaScript - Stack Overflow
とか見ると、昔からみんな混乱してるんだなと分かる。