← 全部文章

纪元时间详解:Unix 时间戳零是什么?

Unix 时间戳 0 是 1970 年 1 月 1 日 00:00:00 UTC。了解为什么那个日期成为 Unix 纪元、负时间戳代表什么、纪元的秒/毫秒/微秒有何不同,以及现代系统适用哪些限制。

Unix 时间戳 0 代表什么

每个 Unix 时间戳都计数自单一参考点——1970 年 1 月 1 日 00:00:00 UTC——以来经过的时间。在 Unix 的原始定义中单位是秒,所以时间戳 0 正好是 1970 年 1 月 1 日的 UTC 午夜,86400 正好是 24 小时之后。现代系统也使用毫秒、微秒和纳秒,但参考点相同。每个正值表示纪元之后的某个瞬间;每个负值表示之前的瞬间。

为什么是 1970 年 1 月 1 日?

这个日期由贝尔实验室的 Unix 开发者在 20 世纪 70 年代初选定,作为略早于 Unix 本身诞生的实用参考点。它需要足够早,使普通系统时间戳为正;足够近,以适配早期计算机的小整数范围;又足够简单,便于心算核对。当 Unix 变得有影响力后,语言、操作系统、数据库、日志格式和网络协议都继承了同一个起点。

  • Unix 自 1969 年起在贝尔实验室开发 —— 纪元设在其稍前
  • 选择 1 月 1 日作为干净的日历边界
  • 用 1970 年而非 1969 年,因为实现使用从零开始的计数器
  • 现代所有操作系统、语言和协议都继承了这个纪元 —— 没有竞争标准

负时间戳:1970 年之前的日期

负的 Unix 时间戳表示 1970 年 1 月 1 日 00:00:00 UTC 之前的瞬间。大多数现代 64 位系统都能正确支持,这对历史数据、出生日期、归档记录,以及与纪元早于 Unix 的系统互操作很有用。较旧的库和数据库可能拒绝负值,因此历史数据集值得做一次显式的兼容性检查。

  • -1 = December 31, 1969 23:59:59 UTC (one second before the epoch)
  • -86400 = December 31, 1969 00:00:00 UTC (one day before the epoch)
  • -2208988800 = January 1, 1900 00:00:00 UTC
  • JavaScript: new Date(-86400 * 1000).toISOString() → '1969-12-31T00:00:00.000Z'

格式的实际上限

Unix 纪元本身不是上限;存储类型才是。存储在 32 位有符号整数中的时间戳,会比存储在 64 位整数、JavaScript 数字或数据库原生 timestamp 类型中的时间戳早得多地失败。评估时间戳安全性时,既要问使用什么单位,也要问用什么数值类型存储。

  • 32-bit signed integer max: 2,147,483,647 = January 19, 2038 03:14:07 UTC (the Year 2038 problem)
  • JavaScript Date max: 8,640,000,000,000,000 ms = September 13, 275760 CE
  • 64-bit signed integer max: ~9.2 × 10^18 seconds = year ~292 billion
  • PostgreSQL TIMESTAMPTZ max: January 1, 294276 CE

其他系统的纪元

Unix 并不是计算中使用的唯一纪元。其他系统出于历史或技术原因定义了自己的参考点。

  • GPS 纪元:1980 年 1 月 6 日 00:00:00 UTC —— 由 GPS 卫星和接收机使用
  • Windows FILETIME:1601 年 1 月 1 日 00:00:00 UTC —— 以 100 纳秒为间隔
  • Apple Cocoa / NSDate:2001 年 1 月 1 日 00:00:00 UTC
  • Excel / Lotus 1-2-3:1900 年 1 月 1 日 —— 为兼容 Lotus 而故意保留的闰年差一错误
  • FAT 文件系统:1980 年 1 月 1 日 00:00:00 本地时间

纪元的秒、毫秒、微秒与纳秒

timestamp 这个词并不总是表明单位。Unix 秒在操作系统和后端语言中常见。Unix 毫秒在 JavaScript 和浏览器 API 中常见。微秒和纳秒出现在数据库、追踪系统和高分辨率日志中。单位同时决定精度和你看到的位数。

  • Seconds: 1700000000 — common in Python, PHP, Go, Ruby, C, and Unix command-line tools
  • Milliseconds: 1700000000000 — common in JavaScript Date and many web analytics systems
  • Microseconds: 1700000000000000 — common in some databases and event pipelines
  • Nanoseconds: 1700000000000000000 — common in high-resolution tracing and systems languages
  • Always document the unit when storing epoch values in APIs, CSV files, and database columns

纪元时间 vs UTC vs 本地时间

纪元时间是一个计数。UTC 是定义参考时刻的全球时间标准。本地时间是基于 America/New_York 或 Asia/Tokyo 这类时区的显示选择。Unix 时间戳不会因用户出行而改变;改变的只是格式化的日历日期和时间。

  • 同一个时间戳在不同时区可能显示为不同的本地日期
  • UTC 输出最适合日志、API 和跨服务器调试
  • 本地输出最适合日历、用户界面和报表
  • 时区偏移在格式化时应用,并不存储在 Unix 时间戳内部

纪元时间常见问题

The Unix epoch (1970-01-01 UTC) was inherited from Multics, the OS that influenced early Unix design. POSIX later standardized the time_t type with explicit semantics that differ from how the original Unix specs described it — and most other platforms count from a different epoch entirely.

  • Multics (1969) counted seconds from 1970-01-01 GMT; Unix adopted the same epoch in 1971
  • POSIX time_t is defined as a count of seconds since 1970 UTC, explicitly excluding leap seconds (every day is 86,400 ticks)
  • POSIX vs Unix terminology: in practice the two are used interchangeably; POSIX is the standardized name
  • Other software epochs differ widely:
  • Windows FILETIME — 1601-01-01 UTC (Gregorian-cycle start), 100-nanosecond intervals
  • .NET DateTime.Ticks — 0001-01-01, 100-nanosecond intervals
  • Apple / Core Data — 2001-01-01 UTC (Cocoa reference date), seconds
  • NTP — 1900-01-01 UTC, seconds; GPS — 1980-01-06, seconds (no leap seconds)
  • Julian Day — noon UT, 4713 BC (proleptic Julian), days
  • When importing time data, confirm the epoch before trusting the value as Unix time

Related articles

FAQ

Is epoch time always in seconds?
The classic Unix timestamp is seconds since 1970-01-01 00:00:00 UTC, but many systems use milliseconds, microseconds, or nanoseconds with the same epoch.
Can Unix timestamps represent dates before 1970?
Yes. Negative timestamps represent dates before the Unix epoch, though older libraries and databases may not support them.
Does a Unix timestamp include a timezone?
No. A Unix timestamp represents one instant in UTC. Timezone information is used only when converting that instant into a readable local date.
What is the maximum Unix timestamp?
It depends on the storage type, not the epoch. A 32-bit signed integer maxes out at 2,147,483,647 (January 19, 2038), while a 64-bit integer or a JavaScript number reaches hundreds of millions of years. See the Year 2038 problem for the details.