ミリ秒 vs 秒:あらゆるアプリを壊す単位の混同

最も一般的なタイムスタンプのバグは、秒が期待される場所にミリ秒を渡す、またはその逆です。10 桁対 13 桁の法則、言語ごとの既定、データベースへの影響、安全な変換パターンを学びます。

なぜ 2 つの標準があるのか

Unix 時間は当初、秒で定義されました。クロックのティックごとに 1 進むシステムには整数が自然でした。JavaScript の Date オブジェクトは 1995 年に導入され、ブラウザでの秒未満のイベント計測のためにミリ秒を選びました。多くのデータベースやバックエンド言語は Unix 秒を既定のまま保ちました。今では両方の標準が JavaScript とサーバーの境界をまたぐすべてのコードに共存し、だからこそ値が一見正しく見えても、数万年先の日付を表していることがあります。

言語ごとに使う単位

分かれ方を覚える最も安全な方法:ブラウザの Date API は通常ミリ秒を求め、Unix 系のサーバー API は通常秒を返し、新しい時間ライブラリは両方を提供することが多い、というものです。サードパーティ API のドキュメントを読むとき、言語だけから単位を推測しないでください。フィールドの説明と例を確認します。

  • Milliseconds: JavaScript Date.now(), Java System.currentTimeMillis(), Java Instant.toEpochMilli(), .NET ToUnixTimeMilliseconds()
  • Seconds: Python time.time() (float), PHP time(), Go time.Now().Unix(), Ruby Time.now.to_i, C time(NULL), PostgreSQL EXTRACT(EPOCH)
  • Both: Rust — duration.as_secs() for seconds, duration.as_millis() for milliseconds
  • Python note: time.time() returns a float, so milliseconds are available as int(time.time() * 1000)

値から単位を自動判別する

現代の日付に対する信頼できる経験則:10 桁の数値は秒、13 桁はミリ秒です。現在の Unix 秒は約 17〜21 億(10 桁)で、13 桁に達するのは西暦 33658 年です。現在の Unix ミリ秒はすでに 13 桁です。この経験則は 2000 年代から数千年先までで最も強力です。歴史的な日付・負の日付・短いテストフィクスチャでは、推測せず明示的な単位を使ってください。

  • 10 桁の値 → 秒(例:1700000000 = 2023-11-14 UTC)
  • 13 桁の値 → ミリ秒(例:1700000000000 = 2023-11-14 UTC)
  • 16 桁の値 → マイクロ秒(秒にするには 1,000,000 で割る)
  • 負の値 → 1970 年 1 月 1 日より前の日付(秒またはミリ秒)

安全な変換パターン

変換自体は単純な算術です。難しいのは、どこで変換するかを選ぶことです。システムの境界で変換し、変換後の値に名前を付け、曖昧な生の数値を複数の層に通さないようにします。

  • Seconds to milliseconds: seconds * 1000
  • Milliseconds to whole seconds — JavaScript: Math.floor(ms / 1000)
  • Milliseconds to whole seconds — Python: ms // 1000
  • Milliseconds to whole seconds — Go: ms / 1000 (integer division)
  • Universal guard in JavaScript: const toMs = ts => ts < 1e11 ? ts * 1000 : ts

単位のバグが本番でどう現れるか

秒対ミリ秒のバグは、どちらの値もただの数値なので、検証をすり抜けがちです。後になって、ありえない日付として現れます:秒をミリ秒として扱うと JavaScript で 1970 年 1 月に、ミリ秒を秒としてバックエンドが扱うと遠い未来の年になります。

  • JavaScript の UI で 1970 年の日付 → 1000 を掛けずに秒を new Date() に渡した
  • Python・Go・PHP で 50000 年以降 → 秒を期待する API にミリ秒を渡した
  • 失効しない期限切れトークン → 失効タイムスタンプを誤った単位で保存した
  • すぐ消えるキャッシュエントリ → ミリ秒を二重に割った、または秒を二重に掛けた
  • 範囲が空の解析チャート → クエリの境界が保存済みイベントのタイムスタンプと異なる単位を使っている

API とデータベースの命名規則

小さな命名規則がこれらのバグの大半を防ぎます。ドキュメントが特に明確でない限り、timestamp という名前の API フィールドを公開しないでください。意味と単位の両方を含むフィールド名を優先します。

  • createdAtMs — Unix milliseconds, best for JavaScript clients
  • createdAtSeconds — Unix seconds, common for backend services
  • createdAtIso — ISO 8601 string, useful for human-readable API responses
  • expiresAtUnixSeconds — explicit enough for auth tokens and signed URLs
  • event_time TIMESTAMPTZ — native database time, with conversion handled by the database

ミリ秒 vs 秒 FAQ

13 桁のタイムスタンプは常にミリ秒?
現代の実在する Unix タイムスタンプでは、はい:13 桁は通常ミリ秒を意味します。非常に遠い未来の秒タイムスタンプも 13 桁に達しうるため、重要なシステムは明示的な単位メタデータを持つべきです。
秒とミリ秒のどちらを保存すべき?
システムが自然に使う単位を保存しつつ、文書化して一貫させてください。JavaScript 中心のシステムはミリ秒を、Unix 系バックエンドや多くのデータベースは秒またはネイティブの datetime 列をよく使います。
なぜ ms / 1000 ではなく Math.floor(ms / 1000)?
Unix 秒は通常整数秒です。Math.floor は小数部を取り除き、整数秒を期待する API に小数が渡らないようにします。
ミリ秒を秒に変換するには?
1000 で割って小数を捨てます:JavaScript は Math.floor(ms / 1000)、Python は ms // 1000、Go は整数除算の ms / 1000。逆方向は秒を 1000 倍します。