JavaScript の日時計算は Date オブジェクトが基本ですが、タイムスタンプの扱い、UTC とローカル時刻の変換、タイムゾーン対応など、深く理解しておくべきポイントが多くあります。この記事では Date の加算・減算・差分といった基本操作は関連記事に譲り、タイムスタンプ・UTC・タイムゾーン・ライブラリ活用・Temporal API など一歩進んだ内容を体系的にまとめます。
・タイムスタンプ(UNIX エポック)の取得と Date への変換
・UTC とローカル時刻の違い・getUTC 系メソッド
・Intl.DateTimeFormat によるタイムゾーン変換
・date-fns と Day.js の比較と導入方法
・Temporal API の概要と基本操作
・日時計算でよくあるバグの回避方法
タイムスタンプ(UNIX エポック)の取得と変換
タイムスタンプは 1970 年 1 月 1 日 00:00:00 UTC(UNIX エポック)からの経過ミリ秒です。JavaScript のタイムスタンプはミリ秒単位ですが、他の言語や API では秒単位の場合があるため注意が必要です。
// 方法1: Date.now()(最も高速) const ts1 = Date.now(); console.log(ts1); // 1775145600000(ミリ秒) // 方法2: getTime() const ts2 = new Date().getTime(); // 方法3: 単項 + 演算子 const ts3 = +new Date();
// ミリ秒タイムスタンプ → Date const date1 = new Date(1775145600000); console.log(date1.toISOString()); // "2026-03-31T00:00:00.000Z" // 秒タイムスタンプ(UNIX time)→ Date const unixTime = 1775145600; const date2 = new Date(unixTime * 1000); // 1000倍してミリ秒に console.log(date2.toISOString()); // "2026-03-31T00:00:00.000Z"
| 環境 | タイムスタンプの単位 | 変換 |
|---|---|---|
| JavaScript | ミリ秒 | そのまま new Date(ms) |
| UNIX / Python / PHP | 秒 | new Date(sec * 1000) |
| MySQL UNIX_TIMESTAMP | 秒 | new Date(sec * 1000) |
UTC とローカル時刻の違い
new Date() で生成される Date オブジェクトは内部的にUTCで値を保持しますが、getHours() などの get 系メソッドはローカルタイムゾーンの値を返します。
const date = new Date("2026-03-31T00:00:00Z"); // UTCの0時
// ローカル(日本: UTC+9)
console.log(date.getHours()); // 9(日本時間の9時)
console.log(date.getDate()); // 31
// UTC
console.log(date.getUTCHours()); // 0(UTCの0時)
console.log(date.getUTCDate()); // 31
get 系と getUTC 系の対応表
| ローカル | UTC | 取得する値 |
|---|---|---|
getFullYear() |
getUTCFullYear() |
年 |
getMonth() |
getUTCMonth() |
月(0〜11) |
getDate() |
getUTCDate() |
日 |
getHours() |
getUTCHours() |
時 |
getMinutes() |
getUTCMinutes() |
分 |
getDay() |
getUTCDay() |
曜日(0〜6) |
タイムゾーンオフセットの取得
const offset = new Date().getTimezoneOffset(); console.log(offset); // -540(日本は UTC+9 → -9*60 = -540分) // 時間単位に変換 console.log(-offset / 60); // 9
getTimezoneOffset() はUTC からローカルへの差分を分単位で返すため、日本(UTC+9)では -540(負の値)になります。符号に注意してください。Intl.DateTimeFormat でタイムゾーンを変換する
Date オブジェクトにはタイムゾーンを変更するメソッドがありません。別のタイムゾーンで表示するには Intl.DateTimeFormat か toLocaleString の timeZone オプションを使います。
const date = new Date();
// 日本時間で表示
console.log(date.toLocaleString("ja-JP", {
timeZone: "Asia/Tokyo"
}));
// "2026/3/31 9:00:00"
// ニューヨーク時間で表示
console.log(date.toLocaleString("ja-JP", {
timeZone: "America/New_York"
}));
// "2026/3/30 20:00:00"(EDT: UTC-4)
// ロンドン時間で表示
console.log(date.toLocaleString("ja-JP", {
timeZone: "Europe/London"
}));
// "2026/3/31 1:00:00"(BST: UTC+1)
const options = {
timeZone: "America/New_York",
year: "numeric", month: "2-digit", day: "2-digit",
hour: "2-digit", minute: "2-digit",
timeZoneName: "short"
};
console.log(new Date().toLocaleString("en-US", options));
// "03/30/2026, 08:00 PM EDT"
date-fns と Day.js の比較
標準の Date だけでは複雑な日時計算が冗長になります。モダンな日時ライブラリとして date-fns と Day.js が広く使われています。
| 比較項目 | date-fns | Day.js |
|---|---|---|
| 設計思想 | 関数型(個別インポート) | Moment.js 互換のチェーン型 |
| バンドルサイズ | 使う関数だけ(Tree-shaking 対応) | コア約 2KB + プラグイン |
| ミュータブル | イミュータブル | イミュータブル |
| TypeScript | 型定義内蔵 | 型定義内蔵 |
| タイムゾーン | date-fns-tz で対応 | dayjs/plugin/utc + timezone |
| 学習コスト | 関数名を覚える必要あり | Moment.js 経験者は低い |
import { addDays, format, differenceInDays } from "date-fns";
const today = new Date();
// 7日後
const nextWeek = addDays(today, 7);
// フォーマット
console.log(format(nextWeek, "yyyy/MM/dd")); // "2026/04/07"
// 日数差分
console.log(differenceInDays(nextWeek, today)); // 7
import dayjs from "dayjs";
const today = dayjs();
// 7日後
const nextWeek = today.add(7, "day");
// フォーマット
console.log(nextWeek.format("YYYY/MM/DD")); // "2026/04/07"
// 日数差分
console.log(nextWeek.diff(today, "day")); // 7
date-fns(Tree-shaking でバンドルサイズ最小化)が推奨です。Moment.js からの移行なら API が似ている Day.js が移行コスト低めです。Moment.js 自体は公式にメンテナンスモードとなっており、新規採用は非推奨です。Temporal API(次世代の日時 API)
Temporal は Date の設計上の問題を根本から解決する新しい日時 API です。2026 年現在 TC39 Stage 3 で、ブラウザの実装が進行中です。
Date の問題点と Temporal の解決策
| Date の問題 | Temporal の解決 |
|---|---|
| ミュータブル(setDate で元が変わる) | イミュータブル(常に新しいオブジェクトを返す) |
| 月が 0 始まり(1月 = 0) | 1 始まり(1月 = 1) |
| タイムゾーン操作が弱い | Temporal.ZonedDateTime で完全対応 |
| 文字列パースが不安定 | 厳密なフォーマット解析 |
| 「日付のみ」「時刻のみ」が表現できない | PlainDate / PlainTime で分離 |
// 現在の日時(タイムゾーン付き)
const now = Temporal.Now.zonedDateTimeISO("Asia/Tokyo");
// 日付のみ
const date = Temporal.PlainDate.from("2026-03-31");
console.log(date.month); // 3(1始まり!)
// 7日後(イミュータブル)
const nextWeek = date.add({ days: 7 });
console.log(nextWeek.toString()); // "2026-04-07"
// 差分
const diff = date.until(nextWeek);
console.log(diff.days); // 7
@js-temporal/polyfill)が必要です。日時計算でよくあるバグとその回避
| バグ | 原因 | 回避方法 |
|---|---|---|
| 月がずれる | getMonth() が 0 始まり |
表示時に +1、設定時に -1 |
| 日付文字列が UTC で解釈される | "2026-03-31" は UTC として解釈される(ブラウザ依存) |
new Date(2026, 2, 31) で直接指定 |
| 1月31日の 1 月後が 3 月になる | setMonth の自動繰り上がり |
月末補正を入れる |
| 夏時間で日数計算がずれる | DST 切り替え日をまたぐと 1 日が 23/25 時間 | UTC ベースで計算するか Math.round を使用 |
| 元の Date が変わってしまう | Date はミュータブル | new Date(original) でコピーしてから操作 |
// NG: 元の date が変わってしまう
const date = new Date("2026-03-31");
date.setDate(date.getDate() + 7);
console.log(date); // 2026-04-07(元の3/31が消えた!)
// OK: コピーしてから操作
const original = new Date("2026-03-31");
const future = new Date(original);
future.setDate(future.getDate() + 7);
console.log(original); // 2026-03-31(元は変わらない)
console.log(future); // 2026-04-07
関連記事
- 日付を操作する方法 — 加算・減算・比較・月末取得・曜日判定
- 日時の差分を計算する方法 — 日数・年齢計算・相対表示
- 日付を取得する方法 — Date オブジェクト・年月日時分秒・フォーマット
- 日付のフォーマットを変換する方法
- 文字列を Date 型に変換する方法
- Intl API を使った日付・数値の国際化フォーマット
よくある質問
new Date(timestamp * 1000) でミリ秒に変換してから Date に渡してください。date-fns(Tree-shaking 対応)。Moment.js からの移行なら API が似ている Day.js。どちらもイミュータブルで TypeScript 対応です。Moment.js は新規採用非推奨です。@js-temporal/polyfill)が必要です。月が 1 始まり、イミュータブル、タイムゾーン完全対応など Date の問題を解決する設計になっています。"2026-03-31")は仕様上 UTC として解釈されますが、ブラウザによって挙動が異なる場合があります。確実にローカル時刻で作成するには new Date(2026, 2, 31) のようにコンストラクタの引数で直接指定してください。new Date(original) でコピーしてから操作すれば元の値を保持できます。根本的な解決には date-fns(常に新しい Date を返す)か、将来の Temporal API(イミュータブル設計)を使います。まとめ
JavaScript の日時計算を体系的に整理しました。
- タイムスタンプ: JavaScript はミリ秒、UNIX / PHP は秒(1000 倍で変換)
- UTC とローカル: get 系はローカル、getUTC 系は UTC を返す
- タイムゾーン変換:
toLocaleStringのtimeZoneオプション - ライブラリ: date-fns(関数型)か Day.js(チェーン型)を選択
- Temporal API: 月 1 始まり・イミュータブル・TZ 完全対応の次世代 API
- バグ回避: 月の 0 始まり・Date のコピー忘れ・文字列パースの UTC 解釈に注意
日付の加算・減算・差分計算の詳細は「日付を操作する方法」「日時の差分を計算する方法」で解説しています。合わせて読むことで日時処理の全体像を把握できます。