DevKitLab Logo DevKitLab
タイムゾーン / UTC / ISO 8601 / 日付と時刻

UTC、GMT、ISO 8601、Unix タイムスタンプの違いは?

UTC、GMT、末尾の Z、+08:00、十桁の数字——まるで同じものかのように使われ、それらを取り違えるところから時間のバグが忍び込みます。これらは「時刻」の変種ではなく、四つの別々の層にあります。基準となる尺度、タイムゾーン、オフセット、そして一つの瞬間を書き留める二つの記法を、それぞれの場所に戻します。

あなたは同じ瞬間に何度も出会う。ただ、そのたびに違う服を着ている。同僚は「全部 UTC で保存しておけ」と言う。ある API は "2026-07-16T09:00:00Z" を返してくる。設定ファイルは GMT+8 を欲しがる。データベースのある列には 1700000000 が入っている。カレンダーの招待には 2026-07-16T17:00:00+08:00 と書いてある。どれも「時刻」を言っているように見えるので、互換なものとして扱っても安全に思える——Z の付いたものを GMT として読み、カレンダー文字列からオフセットを外し、API の値を変換せずにタイムスタンプ列へ入れる。そして何かが八時間ずれる、あるいは来春に会議が誤った日付に落ちる。しかも、なぜなのか誰にも見えない。

こう捉え直すと、全体が整理できる。この五つは、同じものの五つの名前ではない。四つの別々の層にあって、それぞれ別の問いに答えている。一つは基準の尺度——すべての時計がそれに対して測られる、あの線だ。一つはタイムゾーン——名前を持つ地域で、その規則が、地域の時計がその線からどれだけ離れるか・いつ変わるかを決める。一つはオフセット——その規則がある特定の瞬間に出す、固定した +HH:MM。そして二つは記法——同じ一つの瞬間を書き留める方法で、片方は文字として、もう片方は数字として書く。これらを取り違えるのは、無害な言い間違いではない。ものさし、測る規則、そして出てきた測定値を混同することだ。

この記事は、この山をその層に仕分ける。UTC が実際には何なのか(場所ではなく基準の尺度)。なぜ GMT が二つの意味を持ち、UTC の代わりにも「英国の時刻」の代わりにもならないのか。そして最も多くの実バグを生む区別——Asia/Shanghai のようなタイムゾーンと、それが今日たまたま出すオフセット +08:00 は別物であること、そしてその隙間に潜む GMT+8Etc/GMT+8 の罠。さらに ISO 8601 とは何か(時刻ではなく書き方)、その文字列が本当に時刻順に並ぶのはいつか、そして Z が何を意味するか。最後に、それらがどう噛み合うか——「UTC で保存」「ISO 文字列をくれ」「1700000000」が競い合うのをやめ、同じ瞬間を別々の角度から描くように。これはUnix タイムスタンプがずれる理由の姉妹編だ。あちらはその数字の話、こちらはその周りにある名前すべての話である。

唯一の核心:四つの層であって、五つの同義語ではない

これらの語を四つの役割へ仕分ければ、混乱がほどける。

  • 基準の尺度——UTC。他のすべての時計がそれを基準に定義される、合意された一本の線。場所ではなく、誰の壁時計もそれを表示する必要はない。
  • タイムゾーン——Asia/ShanghaiEurope/London。名前を持つ地域で、規則の歴史をまるごと抱えている:さまざまなオフセット、夏時間の切り替え、そしてそれらの規則の過去のすべての変更。これらは IANA タイムゾーンデータベースの中に生きている。
  • オフセット——+08:00-05:00Z。ある瞬間における UTC からの固定した時間数——タイムゾーンの規則がある瞬間に出す値であって、タイムゾーンそのものではない。
  • 記法——ISO 8601 の文字とタイムスタンプの数字。一つの瞬間を釘付けにする二つの方法。ISO 8601 は人が読める文字として書き、Unix/POSIX タイムスタンプは一つの数字として数える。Z か数値オフセットを帯びた ISO 8601 文字列、そして Unix/POSIX タイムスタンプは、ある瞬間を UTC を基準に指し示せる。

だから、基準は一つ(UTC)、規則を抱えたタイムゾーン、その規則がある瞬間に出すオフセット、そして瞬間の二つの綴り。GMT だけが自分の層を持たない語だ——後で見るように、二つの層のあいだを漂ってきたからである。

UTC:基準の尺度であって、あなたが住むゾーンではない

UTC——協定世界時——は基準となる時間の尺度であって、タイムゾーンではない。世界が時間を測る基準として合意した主となる線で、地球規模の原子時計の集合によって維持され、地球の実際の自転から離れすぎないよう、たまの閏秒で微調整される。地球上のあらゆる民用時刻は、UTC にプラスマイナスいくらかのオフセットとして定義される。(この頭字語は、英語順でもフランス語順でもないよう、わざとそうしてある——どの言語もそれを「所有」しないための委員会の妥協だ。)

日々のコードにとって重要な帰結が二つある。

  • 誰も UTC を表示する必要はないが、全員が同じ基準を使える。東京では壁時計が UTC+9 を示し、シカゴは UTC−6 か −5 を示す。そのどちらも同じ瞬間を同じ基準に対して表したものだ。だからこそ「確定した瞬間は UTC で保存しろ」は良い助言になる——二台のサーバー、あるいは二人のユーザーが決して食い違わない、唯一の読みだからだ。(「確定した」に注意——未来のローカルな約束は例外で、その理由は後で扱う。)
  • UTC は夏時間を決して実施しない。固定した基準であり、前へ進めない。夏時間(DST)はタイムゾーンがその上に足すものだ。だから保存された UTC 時刻が「夏になると一時間ずれて見える」とき、動いたのは UTC ではなく、タイムゾーン変換のほうだ。

今の背景を一つ。2026 年なので触れておく——閏秒の仕組み自体が変わろうとしている。2022 年、国際度量衡総会は UT1−UTC(UTC と地球の自転のあいだの差)の許容上限を 2035 年またはそれ以前に引き上げることを決議した。これにより、現行の規則で定期的に閏秒を入れる必要はなくなると見られている。だから「たまの閏秒」は、すでに変更が予定された仕組みであって、宇宙の永遠の法則ではない。いずれにせよ引退させるべき誤解はこれだ——UTC を「ロンドンの時刻」や「GMT」として扱うこと。それは壁時計が測られる元の線であって、そのうちの一つではない。

GMT:一つのラベル、二つの意味

GMT——グリニッジ標準時——は UTC のきれいな同義語ではない。二つの異なる意味を持つからだ

  1. 歴史的には、時間の尺度:グリニッジ子午線における平均太陽時で、地球の自転に結びついている(今日 UT1 と呼ばれるものと密接に関係する)。1880 年代から世界の基準であり続け、原子時計で定義された UTC が 1970 年代にそれを引き継いだ。
  2. 現代の日常的な用法では、ゼロオフセットのラベル:UTC+00:00 の代わりだ。誰かが「14:00 GMT」と言うとき、ほぼ常に UTC を指し、両者は一秒をはるかに下回る差で一致する——サブ秒の精度を気にしないなら十分に近い。

ログや気軽な調整なら、「GMT」を UTC として読んで害はない。だが二つのガードレールは持っておくこと。

  • 保存したデータを錨で留める基準が要るなら、GMT ではなく UTC と言え——UTC は精密な現代の尺度、GMT は曖昧な語で、歴史的な尺度を指すこともゼロオフセットのラベルを指すこともある。
  • 「GMT」は一年中「英国の時刻」ではない。英国は冬に GMT を使うが、夏には BST(英国夏時間、UTC+1)へ切り替わる。だからコードでは、GMT を英国の意味でハードコードするな——BST を知っている IANA タイムゾーン Europe/London を使え。ラベルとしての GMT は決して動かないが、ロンドンの壁時計は動く。

本当に厄介なのはこれ:タイムゾーンはオフセットではない

これは覚えておく価値のある区別だ。本番環境に入り込む、目立たない時間バグの源だからである。Asia/Shanghai+08:00 は、同じことを言う二つの言い方ではない——二つの異なる層だ。

  • タイムゾーン——Asia/ShanghaiEurope/BerlinAmerica/New_York——は、規則の歴史をまるごと抱えた、名前を持つ地域だ:現在のオフセット、夏時間を実施するか・いつするか、そしてそれらの規則の過去のすべての変更。これらは、あなたの OS と言語ランタイムに同梱される IANA タイムゾーンデータベースの中にあり、そのデータベースは年に数回更新される——多くは、ある政府が政治的決定で自国の時計を変えるからだ。タイムゾーンの規則は凍りついてなどいない。
  • オフセット——+08:00-05:00Z——は、タイムゾーンの規則がある瞬間に出す固定した結果だ。ある瞬間が UTC の前後どれだけ離れていたかを告げるだけで、それ以上は何も言わない。

なぜこの違いが机上の空論でないのか——オフセットは、別の瞬間にオフセットがいくつになるかを告げられない。ベルリンは冬に +01:00、夏に +02:00 だ。未来のイベントを「来年三月、9:00 +01:00」として保存すれば、今日のオフセットを、春の DST 切り替えに落ちるかもしれない日付へ凍りつかせたことになる——そして会議は一時間ずれて発火する。未来のローカルイベントを正しく保存するには、タイムゾーン名とローカル時刻(Europe/Berlin09:00)を保つ必要がある。そうすればオフセットは、その時有効な規則から計算される。(タイムゾーンは、DST の切り替えで一部の壁時計時刻を消したり重複させたりもする——春に前へ進むとき起きない一時間、秋に戻るとき二度起きる一時間——これは「一時間ずれる」バグの別の源で、姉妹編がその場合を扱っている。)

この隙間には三つの罠が潜み、三つとも本物だ。

  • GMT+8+08:00Etc/GMT+8 は同じ文字列ではない+08:00 は ISO/RFC のオフセット(UTC より八時間進んでいる)。GMT+8 は一部のライブラリが受け付ける非公式なラベルだ。だが IANA/POSIX データベースの Etc/GMT+8符号が反転している——それは +8 ではなく UTC−8 を意味する。上海のつもりで Etc/GMT+8 に手を伸ばすと、太平洋に着地する。やり取りには +08:00 を優先し、規則が要るときは Asia/Shanghai のような本物のタイムゾーンを使え。
  • タイムゾーンの略称は曖昧だ——決してパースするなCST は米国中部時間であり、かつ中国標準時であり、かつキューバ標準時だ。IST はインド、イスラエル、そしてアイルランドだ。信頼できるオフセットを何も持たない。表示上の飾りとして扱い、保存するのは IANA 名だ。

一つの瞬間が名前付きのいくつものタイムゾーンでどう落ちるか——各タイムゾーンの本当の規則と DST を適用して——を見たいなら、それこそがタイムゾーン変換ツールの用途だ。凍ったオフセットを仮定するのではなく、タイムゾーンを解決してくれる。

ISO 8601:時刻ではなく、書き方

ISO 8601 は日付と時刻のためのテキスト形式——記法であって、時計ではない。書かれた瞬間が、言語や地域をまたいでも曖昧にならないために存在する——03/04/05 のような当てっこの代わりだ。その形は次のとおり。

2026-07-16T09:00:00Z          ← 日付、「T」、時刻、そして UTC を示す標識
2026-07-16T17:00:00+08:00     ← 同じ瞬間を、オフセットで書いたもの

重要な部品を挙げる。日付はビッグエンディアンYYYY-MM-DD)、文字どおりの T が日付と時刻を分ける。そして人が忘れがちで、しかも最も重要な部品は、末尾の標識——Z か、±HH:MM のようなオフセット——であり、これこそが文字を基準に結びつける紐だ。それがないと、その文字列は錨のないローカル日時にすぎない——欠けているタイムゾーンはアプリケーションが補うしかなく、パーサーは既定のタイムゾーン(多くは実行環境のローカル)にフォールバックするか、値をそのまま拒否する。(その、黙ってローカル時刻へ落ちる挙動こそ、姉妹編の「一日ずれる」バグそのものだ。)

ここで一つの半分の真実を正しておく価値がある。「ISO 文字列はただのテキストとして時系列順に並ぶ」。並ぶ——ただし正規化されてからだ:同じ形式、同じ精度、ゼロ埋めした桁、そして同じオフセット、理想的にはすべて UTC の Z に変換したもの。オフセットを混ぜると、テキストの順序は時刻の順序と一致しなくなる——2026-07-16T20:00:00+08:00 はテキストとして 2026-07-16T13:00:00Z後ろに並ぶが、実際にはより早い瞬間だ(12:00Z 対 13:00Z)。だから「並べ替え可能」という超能力は本物だが、それは正規化された UTC 文字列の性質であって、ISO テキスト一般の性質ではない。

もう二つの補足が、実際の混乱を省いてくれる。第一に、ある API が「ISO 8601 のタイムスタンプを送れ」と言うとき、それはほぼ常に RFC 3339 を指す——ISO 8601 の、より厳格なインターネット向けプロファイルで、完全な日付と時刻、そして必須のオフセット(Z か数値)を求める。素の ISO 8601 は、週日付(2026-W29)や期間(P3DT4H)のような、API ではめったに欲しくないものも許す。第二に、Z+00:00 は完全に等しい——どちらも「オフセットゼロ、これは UTC」と言っている。

「Z」と「Zulu」:いちばん小さな一片

...09:00:00Z の末尾にある Z は、オフセットゼロ、すなわち UTC を示す標識にすぎない。航空や軍事で声に出して読めば「Zulu」——通話表で文字 Z を表す語——なので、ある瞬間が「0900 Zulu」と呼ばれるのを耳にするだろう。Z+00:00 は、オフセットゼロを書く二つの標準の方法だ。「UTC」はその意味を指す平易な呼び名であって、タイムスタンプの末尾に付けられる接尾辞ではない(2026-07-16T09:00:00UTC は正しい形式ではない)。三つとも同じ錨を指すが、構文なのはそのうち二つだけだ。唯一の罠は、Z書き忘れてそれを前提にしてしまうこと——それを帯びるべきだったのに帯びていない文字列は、UTC ではなく、曖昧だ。

その数字:Unix(POSIX)タイムスタンプ

1700000000 を保持している列は、もう一つの記法だ——瞬間を、テキストではなく計数として書く。その規則は正確に述べておく価値がある。「タイムスタンプの数字」という緩い言い方こそ、桁数の混乱が始まる場所だからだ。

  • 計数は Unix 紀元の起点 1970-01-01T00:00:00Z から走る——他のすべてと同じく、UTC に錨を下ろしている。
  • POSIX 時間は秒で数え、意図的に閏秒を無視する(どの日も、ちょうど 86,400 秒として扱う)。おかげで数字は、単純な算術で日付へ可逆に戻せる。
  • 単位は普遍ではない。1700000000(今日は 10 桁)だが、JavaScript の Date.now()ミリ秒1700000000000、13 桁)を返す。マイクロ秒やナノ秒を使うシステムもある。秒をミリ秒が欲しい相手に渡すのは、姉妹編が中心に据えている、あの古典的なバグだ。
1700000000       Unix/POSIX 秒
1700000000000    Unix ミリ秒(JavaScript)

その計数と人が読める日付のあいだを行き来するには——そして値が秒かミリ秒かを確かめるには——Unix タイムスタンプ変換ツールがまさにその変換を行ってくれる。

実際にどう噛み合うのか

一つの瞬間をこれらすべてで表すと、各層は競い合うのをやめる。

瞬間:          ある特定の時刻
タイムスタンプ: 1700000000                    (秒。UTC 基準から数える)
ISO 8601(Z): 2023-11-14T22:13:20Z          (文字。UTC に錨を下ろす)
ISO 8601(+): 2023-11-14T14:13:20-08:00     (同じ瞬間。その日ロサンゼルスが出したオフセット)
タイムゾーン:   「Asia/Shanghai」→ 壁時計では翌日の 06:13

どの行も同じ時刻だ。タイムスタンプの数字と二つの ISO 文字列は、その三つの記法。タイムゾーンの規則がオフセットを出し、それを誰かの壁時計へ戻す。UTC は、それら全部が寄りかかる基準である。だからこそ、あの層ごとの助言は矛盾ではなく一貫している——「UTC で保存」とは瞬間を基準に錨で留めておくこと(タイムスタンプの数字も Z 文字列も、それをやる)、「ISO 文字列をくれ」とはあのテキスト記法を求めること、「ユーザーのタイムゾーンへ変換」とは表示のときに一度だけ、タイムゾーンの規則を使って起きることだ。

判断を、一か所に

現実の問いのほとんどは、何を永続化するかに行き着く。この表がそのほぼすべてを覆う(整数のタイムスタンプと ISO 文字列のどちらを選ぶか、ネイティブの列型をどう取るかは、別の記事で詳しく扱う)。

保存したいものこれを保存する
すでに起きた瞬間(created_at、ログ、監査記録)UTC の瞬間——Unix タイムスタンプ、または Z で終わる ISO 8601 文字列
任意の固定した時点その UTC の瞬間(タイムスタンプの数字か Z 文字列)
未来のローカルイベント(「来年三月、ベルリンの 9:00」)ローカル日時 + IANA タイムゾーン名Europe/Berlin)——裸のオフセットは決して使わない
繰り返すカレンダーイベントローカル時刻 + IANA タイムゾーン + 繰り返し規則
ユーザーに見せるもの新しく保存するものはない——最後の一歩で、保存済みの UTC の瞬間を閲覧者のタイムゾーンへ変換する

二つの習慣がこの表を支える。第一に、「全部 UTC で保存」はほぼ正しいが、大まかすぎる確定した瞬間は UTC で保存するが、未来のローカルな予定はローカル時刻と IANA タイムゾーンで保存する。さもないと規則の変更がそれらを黙って動かす。第二に、語が滲みはじめたら、自分が今どの層にいるかを問え——基準、タイムゾーン、オフセット、記法のどれか——たいてい答えはひとりでに出てくる。

貫く一本の線、そして数字そのものへ戻る一句はこうだ——UTC は基準の尺度。タイムゾーンは規則を抱える。オフセットは、その規則がある瞬間に出す結果。そしてタイムスタンプの計数と ISO 文字列は、その瞬間を書き留める二つの方法だ。それぞれの語が層を持った途端、「UTC か GMT か ISO 8601 か」はもはや二者択一ではなくなる——それらははじめから、同じ問いに答えてなどいなかった。

参考規格