本文へスキップ
LeedyBox
支援する

Unix タイムスタンプの解説

Unix タイムスタンプは、ある時点を1つの数値で表したものです。保存や比較は簡単ですが、単位、タイムゾーン、テキストの形式が原因で、変換の誤りがよく起こります。

Unix 時間とは

Unix 時間(エポック時間や POSIX 時間とも呼ばれます)は、Unix エポックである 1970-01-01 00:00:00 UTC からの経過秒数です。0 はエポックそのもの、1700000000 は 2023-11-14 22:13:20 UTC で、負の値は1970年より前の時点を表します。-1 は 1969-12-31 23:59:59 UTC です。

この数値にはタイムゾーンが含まれません。どこでも同じ時点を表すため、出来事の保存、並べ替え、比較に便利です。

Unix 時間はうるう秒を無視し、1日は常にちょうど 86,400 秒です。UTC にうるう秒が挿入されると、システムは1秒を繰り返すか、その1秒をより長い時間に分散させます(「スミアリング」)。そのため、うるう秒をまたぐ時間差は、物理的に経過した時間より1秒短くなります。

秒、ミリ秒、マイクロ秒、ナノ秒のどれ?

多くのシステムはより小さな単位で数えますが、数値を見ただけではどの単位なのかわかりません。同じ時点が、まったく異なる4つの数値として現れることがあります。

単位 2023-11-14 22:13:20 UTC 桁数(2001〜2286年) よく使われる場所
秒 1700000000 10 date +%s、多くの API、JWT の exp クレーム
ミリ秒 1700000000000 13 JavaScript の Date.now()、Java の System.currentTimeMillis()
マイクロ秒 1700000000000000 16 一部のデータベースやログシステム
ナノ秒 1700000000000000000 19 Go の UnixNano()、Python の time.time_ns()

現在に近い日付であれば、桁数を数えるのが最も手早い確認方法です。LeedyBox の変換ツールも同じ考え方を使っており、1011 までの値は秒、1014 まではミリ秒、1017 まではマイクロ秒、それより大きい値はナノ秒として読み取ります。この目安は今日から遠く離れた日付には当てはまらないため、結果がおかしいと思ったら単位を確認しましょう。

精度も重要です。JavaScript の数値が整数を正確に表せるのは 253(約 9 × 1015)までなので、1700000000123456789 のようなナノ秒の値は、通常の数値として解析すると末尾の桁が失われます。このような値は文字列のまま扱うか、BigInt を使いましょう。変換ツールは内部でそのように処理しています。トークンの exp クレームを読むには、Base64 / URL / JWT ツールでトークンをデコードします。

タイムゾーンと夏時間

タイムスタンプを日付と時刻として表示するには、タイムゾーンが必要です。UTC が基準で、現地時間には、ソウルの +09:00 や冬のニューヨークの −05:00 のようなオフセットが加わります。

固定のオフセットや略称ではなく、Asia/Seoul や America/New_York のような IANA タイムゾーン名を使いましょう。名前にはそのゾーンの履歴と夏時間のルールが含まれますが、CST のような略称は複数のゾーンを指します。ルールの元になるタイムゾーンデータベースは年に数回更新され、ブラウザ、OS、プログラミング言語はそれぞれ独自のコピーを持っているため、過去や未来の日付では結果が異なることがあります。

現地時間をタイムスタンプに変換するとき、夏時間によって厄介なケースが2つ生じます。

  • ギャップ: 時計が進められるとき、存在しない現地時刻が生じます。America/New_York では、時計が 02:00 から 03:00 に進むため、2026-03-08 02:30 は飛ばされます。
  • 重複: 時計が戻されるとき、同じ現地時刻が2回訪れます。2026-11-01 01:30 は、EDT(UTC−04:00)で1回、その1時間後に EST(UTC−05:00)でもう1回訪れます。

こうしたケースの扱いはライブラリによって異なります。LeedyBox の変換ツールは、ギャップでは後ろにある有効な時刻(この例では 03:30)を、重複では早いほうの時刻を使い、そのことを注記で説明します。スケジュールされたジョブにも同じ問題があります。cron 式の読み方をご覧ください。

ISO 8601、RFC 3339、HTTP の日付

時点を人が読める形で表す必要がある場合は、ISO 8601 か、そのより厳密なインターネット向けプロファイルである RFC 3339 で書きましょう。

2023-11-14T22:13:20Z
2023-11-15T07:13:20+09:00
2023-11-14T22:13:20.500Z

Z は UTC を意味します。Z かオフセットがあれば、文字列の意味は一つに定まります。2023-11-14T22:13:20 のようにどちらもない文字列は、不明なゾーンの現地時刻であり、パーサーによって解釈が異なります。

Last-Modified や Expires などの HTTP ヘッダーは、メールの日付形式(RFC 2822、現在は RFC 5322)に由来する古い形式を使い、GMT で記述します(例: Tue, 14 Nov 2023 22:13:20 GMT)。

2038年問題

古いシステムの多くは、Unix 時間を符号付き32ビット整数で保存しています。その最大値 2147483647 は 2038-01-19 03:14:07 UTC です。その1秒後にカウンターはオーバーフローして -2147483648 になり、1901-12-13 20:45:52 UTC と解釈されます。現在の OS やプログラミング言語の多くは、数千億年をカバーできる64ビットの時刻値を使っていますが、組み込み機器、ファイル形式、データベースの列、ネットワークプロトコルには、今も32ビットのフィールドが残っています。コードやデータが秒を32ビットで保存しているなら、早めに移行を計画し、2038年以降の日付を今のうちにテストしておきましょう。

コードとデータベースでのタイムスタンプ

JavaScript はミリ秒単位で扱います。

Math.floor(Date.now() / 1000);                  // 現在の Unix 時間(秒)
new Date(1700000000 * 1000).toISOString();      // "2023-11-14T22:13:20.000Z"
Date.parse("2026-10-03T09:00:00+09:00") / 1000; // 1790985600

Python の time.time() は秒を浮動小数点数で返します。tz=timezone.utc を渡さないと、fromtimestamp() はタイムゾーン情報のない、コンピューターの現地時刻を返します。

import time
from datetime import datetime, timezone

int(time.time())                                     # 秒
datetime.fromtimestamp(1700000000, tz=timezone.utc)  # 2023-11-14 22:13:20+00:00
datetime.fromisoformat("2026-10-03T09:00:00+09:00").timestamp()  # 1790985600.0

SQL では、データベースによって関数が異なります。

-- PostgreSQL
SELECT extract(epoch FROM now());   -- 秒(小数部あり)
SELECT to_timestamp(1700000000);    -- timestamp with time zone 型
-- MySQL
SELECT UNIX_TIMESTAMP();
SELECT FROM_UNIXTIME(1700000000);   -- セッションのタイムゾーンで表示

保存については、いくつかの習慣でほとんどの問題を防げます。

  • すでに起きた時点は UTC で保存します。タイムゾーン付きタイムスタンプの列に保存するか、created_at_ms のように単位を列名に含めた64ビット整数として保存しましょう。
  • ソウルで 09:00 に行う会議のような未来の現地の予定は、現地の日付と時刻に IANA ゾーン名を加えて保存し、必要なときにタイムスタンプを計算します。そうすれば、後でルールが変わっても会議の時刻がずれません。
  • 1つの列に複数の単位を混在させないでください。単位を間違えると、1,000倍以上ずれてしまいます。

よくある質問

タイムスタンプを変換すると1970年の日付になるのはなぜですか?

おそらく値を間違った単位で読み取っています。秒をミリ秒として読むと1970年1月になり、ミリ秒を秒として読むと何万年も先の未来になります。桁数を数えるか、変換ツールで単位を選びましょう。

Unix タイムスタンプはタイムゾーンによって変わりますか?

いいえ。Unix タイムスタンプは、UTC の決まった時点からの秒数を数えたものです。タイムゾーンによって変わるのは、それを表示するときの日付と時刻だけです。

Unix 時間でうるう秒を表せますか?

いいえ。Unix 時間はすべての日を 86,400 秒として扱うため、23:59:60 のような UTC 時刻には、それ自体のタイムスタンプがありません。