「本番サーバーのログを見たら、ローカルと9時間ずれてる…」という経験、心当たりがある方も多いと思います。アプリケーション開発においてタイムゾーン周りのバグは地味に厄介で、テスト環境では気づかず本番リリース後にはじめて発覚するケースも珍しくありません。
この記事では、UTC・JST・ISO 8601といった基本的な概念を整理しつつ、JavaScriptやPythonでの実装上の注意点まで順を追って解説します。
タイムゾーンとは?
タイムゾーンとは、地球上のある地域が採用している「標準時」のことです。地球は自転しているため、場所によって太陽が真上に来る時刻(正午)が異なります。それを国・地域ごとにまとめたのがタイムゾーンです。
コードの文脈でタイムゾーンを扱う際には、オフセットとタイムゾーン名という2つの異なる概念を区別することが重要です。
- オフセット:UTCを基準にした時差。
+09:00や-05:00のように表記する固定値 - タイムゾーン名:
Asia/TokyoやAmerica/New_Yorkのように地名で表すもの。夏時間(DST)の切り替えルールも含む
「JST = +09:00 で固定だから同じでは?」と思うかもしれませんが、夏時間を採用している国では同じタイムゾーン名でもオフセットが季節によって変わります。そのためシステム間でやり取りする際はオフセット付きのISO形式か、UTCで統一するのが安全です。
主要な概念を整理する
UTC(協定世界時)
UTC(Coordinated Universal Time)は世界の時刻基準です。オフセットは ±00:00 で、うるう秒を除けばグリニッジ標準時(GMT)とほぼ同じと考えて構いません。サーバー内部やデータベースでは基本的にUTCを使うのがベストプラクティスです。
JST(日本標準時)
JSTはUTCより9時間進んでいます(UTC+9)。日本は夏時間を採用していないため、オフセットは通年 +09:00 で固定です。
ISO 8601形式
日付と時刻を文字列で表現する国際規格がISO 8601です。タイムゾーン情報をオフセットとして末尾に付けるのが特徴です。
2026-01-15T10:30:00+09:00 // JST 2026-01-15T01:30:00Z // UTC(Zはオフセット±00:00を意味する)
APIのレスポンスやログ出力にはこのISO 8601形式を使うことで、受け取り側が確実にタイムゾーンを解釈できます。オフセットなしの 2026-01-15T10:30:00 は曖昧なので避けましょう。
言語別の実装例
JavaScript
new Date() は実行環境のローカル時刻を返しますが、.toISOString() はUTCに変換して返します。この違いを把握していないとバグの原因になります。
const now = new Date();
console.log(now.toString()); // ローカル時刻(実行環境依存)
console.log(now.toISOString()); // UTCのISO 8601形式で出力
// → "2026-01-15T01:30:00.000Z"
// タイムゾーンを指定して表示
const formatted = now.toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' });
console.log(formatted); // "2026/1/15 10:30:00"
Python
from datetime import datetime, timezone, timedelta # タイムゾーンなし(naive datetime)は危険 naive = datetime.now() # UTCで取得(推奨) utc_now = datetime.now(timezone.utc) print(utc_now.isoformat()) # 2026-01-15T01:30:00+00:00 # JSTに変換 jst = timezone(timedelta(hours=9)) jst_now = utc_now.astimezone(jst) print(jst_now.isoformat()) # 2026-01-15T10:30:00+09:00
データベースへの保存はUTCで
MySQLやPostgreSQLにタイムスタンプを保存するときは、UTC基準で統一するのが鉄則です。表示のタイムゾーン変換はアプリケーション側で行います。サーバーの設置場所やユーザーの地域が変わっても、UTCで保存していれば計算がずれません。
-- MySQLでUTC_TIMESTAMPを使う
INSERT INTO events (title, created_at) VALUES ('リリース', UTC_TIMESTAMP());
-- PostgreSQLではTIMESTAMPTZ(タイムゾーン付き)を使う
CREATE TABLE events (
title TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
タイムゾーン変換の計算が面倒なときは タイムゾーン変換ツール を使うと、UIで簡単に確認できます。Unixタイムスタンプとの相互変換は Unixタイムスタンプ変換 が便利です。2つの日時の差を求めたい場合は タイムスタンプ差分計算 も活用してください。
よくある質問
- Unixタイムスタンプはタイムゾーンの影響を受けますか?
- 受けません。Unixタイムスタンプ(エポック秒)は、1970年1月1日00:00:00 UTCからの経過秒数です。タイムゾーンに関係なく世界共通の値なので、異なる地域のシステム間で時刻を比較・保存する際にも安全に使えます。表示する際にタイムゾーンを適用して変換します。
- 夏時間(DST)とは何ですか?
- 夏時間(Daylight Saving Time / DST)は、春から秋にかけて時計を1時間進める制度です。アメリカやヨーロッパの多くの国が採用しています。例えば
America/New_Yorkは通常UTC-5ですが、夏時間中はUTC-4になります。日本は夏時間を採用していないため、JSTは常にUTC+9で固定です。 - JSTとJSTD(日本標準時)は同じものですか?
- 基本的には同じ意味で使われます。ただし「JSTD」という表記は一般的ではなく、公式にはJST(Japan Standard Time)が正式な略称です。システムやIANAタイムゾーンデータベースでは
Asia/Tokyoという識別子が使われます。JSTという略称は他の国の標準時(Jamaica Standard Timeなど)と衝突する場合があるため、コード内ではAsia/Tokyoを使う方が明確です。 - GMTとUTCの違いは何ですか?
- GMT(グリニッジ標準時)はイギリスのグリニッジ天文台を基準とした時刻で、歴史的な概念です。UTC(協定世界時)は原子時計を基準にした現代の国際標準で、GMT後継として定められました。日常的な用途では同一視して問題ありませんが、厳密には定義が異なります。現代のシステムでは「UTC」を使うのが正確です。
まとめ
- UTCは世界の時刻基準。データベースへの保存はUTCで統一する
- JSTはUTC+9で固定(日本は夏時間なし)
- ISO 8601形式でオフセットを明示することで曖昧さをなくせる
- オフセット(+09:00)とタイムゾーン名(Asia/Tokyo)は別概念。夏時間を扱うならタイムゾーン名を使う
- JavaScriptの
new Date()はローカル時刻。toISOString()でUTCに変換できる
タイムゾーン関連の変換・計算には以下のツールを活用してください。
- タイムゾーン変換:世界各地のタイムゾーン間でUIから即変換
- Unixタイムスタンプ変換:エポック秒と日時の相互変換
- タイムスタンプ差分計算:2つの日時の差を時間・分・秒単位で計算