JavaScriptで日付が1日ずれるときは、最初に「時刻を持たない日付」なのか、「ある瞬間」なのかを確認してください。入力した日付をDateへ変換し、さらにUTCや別の地域の時刻として表示すると、カレンダー上の日付が変わることがあります。
この記事では、日付だけの文字列、toISOString()、日付入力欄、タイムゾーン指定の表示を順に確かめます。自作コードをNode.js v26.9.0のUTC・Asia/Tokyo・America/Los_Angelesで実行し、計24項目を確認しました。OS全体の時刻設定は変更せず、実行プロセスごとにタイムゾーンを指定した結果です。
この記事でわかること
- 誕生日・休暇日などの日付だけ:
2026-10-05のような日付として扱う。 - 申込時刻・投稿時刻などの瞬間:タイムゾーン情報を含む日時として扱う。
- 「今日」を表示する:利用者の地域か、日本時間などの固定地域かを決める。
JavaScriptで日付がずれる2つの原因

たとえば2026-10-04T23:30:00Zという日時があります。末尾のZはUTCを表します。この瞬間を東京で表示すると2026年10月5日、ロサンゼルスで表示すると2026年10月4日です。
この違い自体は不具合ではありません。同じ瞬間を別の地域のカレンダーで見ているためです。一方で、利用者が「10月5日の休暇」を選んだだけなら、地域によって10月4日へ変わる表示は意図と合わない場合があります。
MDNのDateの説明では、日時の内部値と、ローカル時間・UTCでの読み取りが区別されています。Dateの中に「日本時間」という地域名が保存されている、と考えないことが出発点です。
原因1:new Date(‘2026-10-05’)を地域の時間で読む
次のコードは、時刻を含まない日付文字列をDateへ変換しています。標準のこの形式はUTCの午前0時として解釈されます。
const date = new Date("2026-10-05");
console.log(date.toISOString());
console.log(date.getFullYear(), date.getMonth() + 1, date.getDate());
1行目の表示は、確認した3環境すべてで2026-10-05T00:00:00.000Zでした。ところがgetFullYear()などで実行環境のローカル日付を読むと、次のように分かれます。
| 実行環境のタイムゾーン | ローカルの日付として読んだ結果 |
|---|---|
| UTC | 2026-10-05 |
| Asia/Tokyo | 2026-10-05 |
| America/Los_Angeles | 2026-10-04 |
ロサンゼルスでは、UTCの10月5日午前0時が現地の10月4日に当たります。「自分のPCでは合っているのに、別の地域の利用者では前日になる」という問題を調べるときの手がかりです。
なお、new Date("2026-10-05T00:00:00")のように日時を書き、オフセットを付けない形式は、実行環境のローカル時間として解釈されます。日付だけの形式と、同じ意味だと思って置き換えないでください。
原因2:日本の午前0時をtoISOStringでUTCへ変える
逆方向のずれもあります。日本時間の午前0時をUTCへ変換すると、日付部分は前日です。
const midnight = new Date("2026-10-05T00:00:00");
console.log(midnight.toISOString());
console.log(midnight.toISOString().slice(0, 10));
Asia/Tokyoで実行した結果は、次のとおりでした。
2026-10-04T15:00:00.000Z
2026-10-04
slice(0, 10)は、文字列の先頭10文字を切り出しているだけです。元の日本時間の日付を取り戻してはいません。toISOStringの公式リファレンスでも、返す日時がUTCであることを確認できます。
このため、new Date().toISOString().slice(0, 10)を「利用者の地域の今日」として使うと、時間帯によっては前日や翌日を表示します。UTCの日付が欲しい場合に使っているのか、先に仕様を確かめましょう。
日付だけを扱うなら、不要なDate変換を避ける

誕生日や受講希望日のように、時刻を持たない日付を入力してもらうなら、日付入力欄の文字列をそのまま扱う選択肢があります。
<label for="study-date">学習日</label>
<input type="date" id="study-date">
const input = document.querySelector("#study-date");
const selectedDate = input.value;
console.log(selectedDate); // 選択済みなら例: "2026-10-05"
MDNの日付入力欄の説明では、画面上の表示が地域に合わせて変わっても、値はyyyy-mm-dd形式になることが示されています。選択していないときは空文字なので、必須かどうかの確認は別に必要です。
この値を保存するのに、必ずDateへ変換してUTC日時にする必要はありません。「2026年10月5日」という日付の意味を保ち、画面ではsplit('-')で年・月・日に分けて表示する方法もあります。
ただし、文字列にしておけば入力チェックが不要になるわけではありません。APIへ送るなら、受け取る側でも形式と実在する日付を確認します。CSVなどから来た任意の文字列が、日付入力欄と同じく有効だとも限りません。
利用者の地域の「今日」は、ローカルの年・月・日から作る
実行環境のローカル日付を表示したいなら、ローカルの年・月・日を読む方法があります。
function localYmd(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
}
console.log(localYmd(new Date()));
getMonth()は0から始まるため、表示用には1を足しています。この関数は、ブラウザならその実行環境の地域の日付、サーバーならサーバー側の地域の日付を返します。常に日本の日付になる関数ではありません。
表示対象の地域を固定したいときは、次のようにタイムゾーンを明示します。「今日」という短い言葉でも、利用者の今日と、日本の今日で要件が異なります。質問例は、英語で仕様を確認する質問集で練習できます。
Intl.DateTimeFormatで日本時間を指定して表示する

記録した瞬間を日本時間で表示したい場合は、Intl.DateTimeFormatのtimeZoneを指定できます。次は同じ瞬間から、指定した地域の年月日を組み立てる例です。
function ymdInZone(instant, timeZone) {
const parts = new Intl.DateTimeFormat("en-US", {
timeZone,
year: "numeric",
month: "2-digit",
day: "2-digit"
}).formatToParts(new Date(instant));
const values = Object.fromEntries(parts.map(part => [part.type, part.value]));
return `${values.year}-${values.month}-${values.day}`;
}
const instant = "2026-10-04T23:30:00Z";
console.log(ymdInZone(instant, "Asia/Tokyo"));
console.log(ymdInZone(instant, "America/Los_Angeles"));
結果は順に2026-10-05と2026-10-04です。実行環境を3種類に変えても、表示対象の地域を指定しているため、この結果は同じでした。Intl.DateTimeFormatのオプションはMDNのリファレンスで確認できます。
この関数へ渡すinstantは、Zやオフセットを持つ日時を想定しています。不正な文字列や、地域の情報が欠けた日時を自動的に正しく補う関数ではありません。入力元の仕様と有効性を別途確認してください。
夏時間と日付の境目をテストする

日付の差を計算するときに、ミリ秒の差を24 * 60 * 60 * 1000で割る方法を見かけます。経過時間として何時間たったかを知る目的と、カレンダー上で何日進んだかを知る目的を分けてください。
今回、America/Los_Angelesのローカル午前0時どうしを引くと、次の結果になりました。
| 確認した区間 | 午前0時から翌日午前0時まで |
|---|---|
| 2026年3月8日→3月9日 | 23時間 |
| 2026年11月1日→11月2日 | 25時間 |
夏時間の切り替わりがあるためです。今回の同じ日付区間では、UTCとAsia/Tokyoは24時間でした。カレンダー上の日数を数えたいのに経過時間を割るだけだと、小数になるなど、期待と違う値が出ることがあります。
予約期間、連続学習日数、締め切りなどを扱う場合は、「日付の差」なのか「正確な経過時間」なのかを決めてから実装します。固定で9時間を足す・引く方法をすべての地域に適用することも避けてください。
日付がずれたときの確認表
| 確認すること | 記録する具体例 |
|---|---|
| 入力の元の値 | 2026-10-05なのか、2026-10-05T00:00:00なのか、末尾にZや+09:00があるか |
| 実行環境の地域 | ブラウザ・サーバーがUTC、Asia/Tokyoなどのどれか |
| 変換した処理 | new Date、toISOString、ローカルのgetDateなど、どこを通ったか |
| 本来欲しい結果 | 入力した日付を保つのか、日本時間へ変換したいのか |
| 確認する境界 | 午前0時付近、月末・年末、必要なら夏時間の切り替わり |
端末の地域はIntl.DateTimeFormat().resolvedOptions().timeZoneで確認できます。原因を調べるためにOS全体の設定を急いで変える前に、入力値・変換処理・期待結果を小さなコードへまとめてください。
英語で相談するときは、I selected October 5, but the app shows October 4. The browser time zone is America/Los_Angeles.のように、選んだ日、表示された日、確認した地域を伝えます。報告の構成は英語のバグ報告テンプレートも使えます。
よくある質問
日付がずれたら、とりあえず9時間足せば直りますか?
何を表す値かを確認してから直します。UTCから日本時間への表示が目的なのか、時刻を持たない日付が欲しいのかで方針が違います。他の地域や夏時間へも同じ足し算を広げることはできません。
toISOStringが間違った日付を返しているのですか?
UTCとしては正しくても、日本のカレンダーの日付とは違う場合があります。日本の午前0時がUTCでは前日になる例を確認してください。欲しい地域の表示と、UTCで保存・出力する処理を区別します。
誕生日もUTCに変換して保存するべきですか?
時刻を持たない日付として扱うなら、日付型や日付文字列として保つ設計が考えられます。データベース、API、画面の間で「日付だけ」という意味をそろえることが大切です。
今回の結果は、すべてのブラウザで検証済みですか?
比較表の結果はNode.js v26.9.0で3つのタイムゾーンを指定して確認したものです。全ブラウザ・全OSの組み合わせを検証したわけではありません。公開するアプリでは、対象ブラウザと必要な地域で入力から保存・再表示まで確認してください。
まとめ:入力・保存・表示で日付の意味をそろえる
日付ずれを調べるときは、最初の値と最後の表示の間で「日付だけ」が「瞬間」へ変わっていないかを見ます。小さな例で確認できたら、JavaScriptの学習記録アプリなどに日付欄を追加する練習へ進めます。現在の教材に日付欄があるという意味ではなく、自分で追加する発展課題です。
作ったものを動かしながら、ITと英語を学びたい方へ
KredoではITと英語を学ぶ留学プログラムを案内しています。現在の学習状況や目標をもとに、自分に合った学び方を相談できます。
英語でIT・AIを学べるKredo
英語×IT・AIのスキルを身につけてグローバルに活躍しませんか?
当メディアを運営しているKredoは、英語×ITをオンラインで学ぶ「Kredoオンラインキャンプ」と、フィリピンのセブ島で英語とIT・AIを学ぶ「KredoIT留学」「KredoAI留学」を提供しています。これまでの卒業生は3,000名以上。卒業生の多くが、国内外のIT企業への転職、フリーランスなどへのキャリアチェンジを実現しています。これからの時代に必要な英語×IT・AIのスキルを身につけてグローバルに活躍しませんか?











