この記事の目次
日本で開くと11月8日なのに、海外から見ると11月7日になる。どちらも同じ開始時点を表しているなら、計算が間違っているとは限りません。ただし「会場の開催日を表示する」という目的なら、閲覧端末に表示地域を任せるのは合いません。
関数と文字列の操作が分かる人向けに、架空の夜間観察会を使います。Node.js 24系とエディターを用意し、通信のない短いスクリプトを実行します。日時の入力画面や繰り返し予定の計算には広げず、一つの時点をどう表示するかを確かめます。
開始時点、表示地域、日付だけの値を分ける
観察会の開始を「2026年11月8日0時30分、日本時間」と決めます。値は2026-11-08T00:30:00+09:00です。この時点はUTCでは11月7日15時30分になります。+09:00はUTCからの時差で、表示の飾りではありません。
Dateは一つの時点を数値として保持します。元の文字列に付いていた+09:00や「東京のイベント」という用途は、そのままDateへ保存されません。MDNのDateの説明に沿い、どの時間帯で読むかを表示側で別に決めます。
| 情報 | この教材での値 | 扱い |
|---|---|---|
| 開始した瞬間 | 2026-11-08T00:30:00+09:00 | Dateへ変換して地域別に表示 |
| 会場での表示地域 | Asia/Tokyo | IntlのtimeZoneへ指定 |
| 時刻を持たない開催日 | 2026-11-08 | 日付として保ち、時点へ変換しない |
日付だけの欄は「午前0時に始まる」という意味を持ちません。HTMLに記す場合の区別はtimeとdatetimeの記事で扱っています。今回は、その値をJavaScriptへ渡す段階でも意味を変えないことが判断の入口です。
一つのDateから、二つの地域の案内を作る
次をevent-time.mjsへ保存し、node event-time.mjsで実行します。入力日時は教材内で確定した値です。Dateの引数へ、意味の曖昧なスラッシュ区切りの文字列を追加しないでください。
const source = '2026-11-08T00:30:00+09:00';
const start = new Date(source);
function formatStart(date, timeZone) {
if (Number.isNaN(date.getTime())) return '日時を確認してください';
return new Intl.DateTimeFormat('ja-JP', {
timeZone,
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', hourCycle: 'h23'
}).format(date);
}
console.log('会場(Asia/Tokyo):', formatStart(start, 'Asia/Tokyo'));
console.log('比較(America/Los_Angeles):', formatStart(start, 'America/Los_Angeles'));
console.log('UTC:', start.toISOString());
console.log('同じ時点:', start.getTime() === new Date('2026-11-07T15:30:00Z').getTime());
console.log('不正な値:', formatStart(new Date('unknown'), 'Asia/Tokyo'));
const eventDay = '2026-11-08';
const [year, month, day] = eventDay.split('-');
console.log(`開催日(時刻なし):${year}年${Number(month)}月${Number(day)}日`);
会場は11月8日00:30、比較先は11月7日07:30です。UTCの行は2026-11-07T15:30:00.000Z、同じ時点の行はtrueになります。Intlが返す区切り記号などは実装やロケールデータで差があり得るため、確認では年・月・日・時・分と、表示に添えた地域を対応させます。
Intl.DateTimeFormatの説明にあるように、一つのDateを複数の書式で表示できます。ここでは表示文に地域名も付け、比較先の11月7日を会場の開催日と取り違えないようにしています。元のstartを書き換える処理はありません。
最後の行は確定済みの年月日を分割した表示です。これは日付の妥当性を検証する関数ではありません。2月30日などの入力検証が必要なアプリへ、そのまま検証処理として使わないでください。
日本語にしたのに日が変わる場合は、timeZoneを見る
第一の失敗は、'ja-JP'を指定したので日本時間になると考えることです。これは言語や表記の指定であり、表示地域の指定ではありません。timeZoneを省略すると、実行環境の時間帯が使われます。コンストラクターのオプションで両者を区別できます。
修正は、会場の案内にtimeZone: 'Asia/Tokyo'を明記することです。macOSやLinuxのターミナルでは、次の二条件で同じファイルを実行して比べられます。環境変数はこのコマンドだけへ渡し、端末全体の時計は変更しません。
TZ=Asia/Tokyo node event-time.mjs
TZ=America/Los_Angeles node event-time.mjs
完成例なら、どちらでも会場の行は11月8日00:30のままです。timeZoneの指定だけを一時的に外したコピーでは、環境によってその行の日時が変わります。言語を英語へ替える修正では、表示地域を固定したことになりません。
手動で9時間を足してから東京時間で整形する修正にも注意します。元の日時が既に+09:00を持つなら、その時差はDateへの変換で考慮されています。さらに足すと別の時点になります。修正後は見える時刻に加え、UTCの行が変わっていないことも確認します。
日付だけをDateへ入れると、別の日を指して見える
第二の失敗は、開催日だけの2026-11-08をDateへ入れ、各地域の日時として表示することです。次を完成例の末尾へ一時的に足せます。
console.log(formatStart(new Date('2026-11-08'), 'America/Los_Angeles'));
この日付形式はUTCの午前0時として解釈されるため、結果はロサンゼルスの11月7日16:00です。日付の見た目を整えたいだけなのに、勝手に開始時点を作ったことが原因です。修正は、完成例のeventDayのように、時刻を持たない値を日付のまま表示すること。地域を変えても「2026年11月8日」を保つか再確認します。
一方、2026-11-08T00:30:00のように時刻を含み、時差を省略した形式はローカル時間として解釈されます。開始時点を共有したいデータなら、日時を提供する側と時差を含む形式を決めます。後から思い込みでZを付けると、元の時刻とは別の意味になり得ます。
地域を固定する表示と、利用者の地域で見る表示
会場での集合案内には会場の地域を、オンライン配信を各自の時計で見る案内には利用者の地域を使う設計が考えられます。後者でも「あなたの地域の時刻」と地域名を添え、元の開催地域の表示も必要かを判断します。全部を日本時間へそろえること自体が目的ではありません。
また、+09:00という時差と、Asia/Tokyoという地域名は役割が違います。夏時間のある地域では、日時によってUTCとの時差が変わります。将来の毎週開催や営業日計算では地域の規則も必要なので、今回の一時点の表示だけで予定管理を組み立てないようにします。
formatStartの不正値分岐も、Dateが無効になった場合を扱うだけです。入力書式の全検証や、存在しない日付の厳密な拒否を保証しません。表示前に確認すべきデータの条件と、表示する地域を分けて記録します。
日付の境目をまたぐ三条件で照合する
15分程度の練習では、最初の日時、同じ時点のUTC表記、不正な文字列を順に試します。日本の昼だけで確認すると、前日へ移る条件を見落とします。
| 入力・条件 | 期待する結果 |
|---|---|
| 最初の日時を東京で表示 | 11月8日00:30 |
| 同じ日時をロサンゼルスで表示 | 11月7日07:30 |
| 入力を2026-11-07T15:30:00Zへ変更 | 二地域の表示はともに変わらない |
| unknownから作ったDate | 日時を確認してください |
| 日付だけのeventDay | 2026年11月8日。時刻を付けない |
JavaScriptの無料レッスンで表示処理へつなぐ場合も、元の値、整形する関数、表示先を分けて追えます。同じ時点を別の表記で渡して結果が変わらず、日付だけの欄に時刻が混ざらなければ、今回の確認は完了です。
TRY A LESSON
記事の内容を、課題で確かめる
記載内容へのご質問や訂正のご連絡は、hello@junkbranding.comまでお願いします。