JavaScript の日付を「日本時間の YYYY-MM-DD」にしたいときの書き方と落とし穴

に公開2

フロントエンドで「カレンダーで選んだ日付を YYYY-MM-DD 形式の文字列にしたい」という場面、よくありますよね。

友人のコードを見ていたら、こんな書き方をしていました。

const isoDate = selectedDate.toLocaleDateString("ja-JP", {
  year: "numeric",
  month: "2-digit",
  day: "2-digit",
}).replace(/\//g, "-");
  • toLocaleDateString("ja-JP", ...)2025/11/21
  • /- に置き換えて 2025-11-21

という流れです。
これでももちろん動きますが、ChatGPT に「もっといい書き方ない?」と聞いたところ、こんなコードを提案されました。

const isoDate = new Date(
  selectedDate.getTime() - selectedDate.getTimezoneOffset() * 60 * 1000,
)
  .toISOString()
  .slice(0, 10);

ここで湧いた疑問がこれです。

この書き方だと "ja-JP""Asia/Tokyo" も書いてないのに、なんで日本時間になるの?

この疑問をきっかけに、UTC と getTimezoneOffset()、そして「JavaScript がどうやって自分のタイムゾーンを判断しているか」を整理してみます。


そもそも UTC とは?

UTC(Coordinated Universal Time / 協定世界時) は、世界中で使われる基準となる時間です。
各国のローカルタイムは、UTC を基準にして「+何時間」「−何時間」という形で決まっています。

  • 日本(JST) = UTC + 9時間
  • アメリカ(ニューヨーク) = UTC −5時間

昔は GMT(グリニッジ標準時)が使われていましたが、現在の正式な基準は UTC です。
GMT とほぼ同じですが、UTC は原子時計をベースにした、より精密な定義になっています。


getTimezoneOffset() とは何か?

getTimezoneOffset() は JavaScript の Date オブジェクトに用意されているメソッドで、

「その日時のローカルタイムゾーンと UTC の“差”を、分単位で返す」

というものです。

例:

const d = new Date();
const offset = d.getTimezoneOffset();
console.log(offset);

日本(JST, UTC+9)の環境で実行すると、だいたいこうなります。

-540
  • 540分 = 9時間
  • マイナスなのは「UTC − ローカル時間」の差として定義されているから
    (UTC よりローカルが進んでいるとマイナスになる)

「日本」とはどこにも書いてないのに、なぜ日本時間になるのか?

ポイント:JavaScript は OS のタイムゾーン設定を見ている

getTimezoneOffset() 自体には「日本」という文字列は一切出てきません。
代わりに、JavaScript(ブラウザや Node.js)は実行環境の OS のタイムゾーン設定を見ています。

  • macOS / Windows の「日付と時刻」の設定で
    タイムゾーンが「大阪 / 札幌 / 東京」になっている

  • その状態で new Date()getTimezoneOffset() を呼ぶ

  • JavaScript は

    「この環境のローカルタイムゾーンは JST (UTC+9) なんだな」
    と解釈する

  • その結果として getTimezoneOffset()-540 を返す

つまり:

どこかで「日本です」とコードに書いているわけではなく、
「OS が日本時間になっているから、結果として日本時間として扱われている」

だけです。

同じコードをアメリカの PC で動かすと別の値(例:300 = 5時間分)が返ってきます。


何が嬉しいのか?

このトリックはざっくり言うと、

「ローカルで選んだ日付を、日付としてズレないようにしたまま YYYY-MM-DD を取り出す」

ためのテクニックです。

  • toISOString() は UTC で文字列を作るので、そのまま使うと日付がズレる場合がある
  • そこで事前にローカルタイムの分だけ時間を補正してから toISOString() している

日本の PC で使うと、結果的に日本時間ベースの日付になりますが、
それは OS が日本時間だからそうなっているだけで、
このコード自体が「日本固定」なわけではありません。

Discussion

junerjuner

それなら getTime() 外してもよさそうですね Date 型のプリミティブは getTime() の数値なので

const isoDate = new Date(
  selectedDate - selectedDate.getTimezoneOffset() * 60 * 1000,
)
  .toISOString()
  .slice(0, 10);