找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2344

积分

0

好友

342

主题
发表于 2025-12-31 01:38:20 | 查看: 22| 回复: 0

时间发展史

早期计时方案

人类对时间的测量始于对自然周期的观察。早期文明通过月相和太阳的运动,将时间划分为日、月、年等可管理的单位。

随着社会发展,更精细的时间划分成为必要。古埃及和巴比伦人受到以12为基数的数字系统影响,将一天分为24小时。此后,1小时被划分为60分钟,1分钟又被划分为60秒,形成了沿用至今的时间框架。

原子钟时间

虽然早期方法沿用了数个世纪,但其核心问题在于精度不足。20世纪50年代原子钟的发明彻底改变了这一局面。原子钟依据铯原子的振动来测量时间,提供了无与伦比的精确度。

原子钟数字显示
图1:显示时间、温度、湿度等信息的数字时钟

基于原子钟,秒被重新定义为:

铯-133原子基态的两个超精细能级之间跃迁对应的辐射的9,192,631,770个周期的持续时间。

这一定义后来成为了国际原子时(TAI)的基础。

JavaScript 中的几种时间标准

UT(世界时)

世界时(Universal Time, UT)是一种基于地球自转的时间系统,但其准确性存在固有缺陷,主要原因如下:

  1. 地球自转的不均匀性
    • 长期减慢:由于潮汐摩擦等因素,地球自转速度在长期上逐渐减慢,导致一天的实际长度缓慢增加。
    • 短期波动:大气运动、地震、冰川融化等也会引起地球自转速度的短期波动。
  2. 天文观测的不确定性
    • 观测误差:通过观测恒星位置来确定世界时,会受到天气、仪器精度等因素影响。
    • 数据处理:复杂的观测数据处理和校正过程也可能引入误差。

TAI(国际原子时)

原子时直接源自原子钟,基于稳定的物理现象,既精确又一致,是现代计时系统的核心支柱。

UTC 时间

1972年,协调世界时(Coordinated Universal Time, UTC)被引入,用以协调世界时与原子时之间的差异。UTC在概念上与世界时保持一致,但会通过增加或删除闰秒来补偿地球不规则的自转。

GMT(格林威治标准时间)是基于地球自转的一种时间标准,常被认为是UTC的前身。

闰秒是为了保持UTC与地球自转同步而偶尔添加(或理论上删除)的1秒调整,确保两者误差在0.9秒以内。然而,闰秒给依赖精确计时的系统带来了诸多复杂性。

世界时区分布地图
图2:展示全球不同时区分布的世界地图

UTC是一个全球统一的时间标准,本身不考虑时区差异,但可以通过加减时区偏移量来转换为本地时间。

JavaScript中,Date.UTC()静态方法接受与Date构造函数相似的参数,但将其视为UTC时间,并返回自1970年1月1日00:00:00 UTC以来的毫秒数。

const utcDate1 = new Date(Date.UTC(96, 1, 2, 3, 4, 5));
const utcDate2 = new Date(Date.UTC(0, 0, 0, 0, 0, 0));

console.log(utcDate1.toUTCString());
// 输出: "Fri, 02 Feb 1996 03:04:05 GMT"
console.log(utcDate2.toUTCString());
// 输出: "Sun, 31 Dec 1899 00:00:00 GMT"

console.log('The time in the UTC+0 timezone is' + utcDate1.toISOString()); // UTC 0时间,即ISO格式
console.log('Your local time is' + new Date().toLocaleString()); // 本地时间

JavaScript 中的秒时长

ECMAScript 采用 POSIX 时间,忽略闰秒

ECMAScript标准定义的JavaScript时间系统基于POSIX(可移植操作系统接口)时间。这意味着日期和时间以自Unix纪元(1970年1月1日00:00:00 UTC)以来经过的毫秒数来衡量,并且不包括闰秒

const start = Date.now();
console.log("starting timer...");
// Date.now() 静态方法返回自纪元以来经过的毫秒数
setTimeout(() => {
  const millis = Date.now() - start;
  console.log(`seconds elapsed = ${Math.floor(millis / 1000)}`);
  // Expected output: "seconds elapsed = 2"
}, 2000);

该系统固定认为每天有86,400秒(24小时),无视闰秒和地球自转的天文变化。虽然这简化了计算并能满足大多数应用需求,但在要求极端精确计时的场景下存在局限。

POSIX 时间 ≠ UTC 时间

尽管POSIX和UTC都基于相同的纪元起点,但两者存在核心区别:

UTC时区参考图
图3:以UTC为基准的世界时区地图

  • POSIX忽略闰秒:UTC通过插入闰秒来对齐地球自转,而POSIX时间始终假设每天为86,400秒。即使在UTC日长为86,401或86,399秒的闰秒日,POSIX时间也保持不变。
  • 时间精度:POSIX时间通常精确到秒(或毫秒),而UTC时间可精确到纳秒级。
  • 时区处理:两者都基于零时区,时区转换均通过加减偏移量实现。
  • 简化互操作性:POSIX假设所有秒的持续时间相等,使得计算时间差变得简单直接,但在发生闰秒时会产生偏差。

例如,在UTC时间23:59:60(闰秒)这一刻,POSIX时间会完全忽略这一秒,导致闰秒附近的时间戳可能出现歧义或不准确。

// ISO 8601格式的UTC时间,'Z'表示零时区(UTC+0)
const utcDate = new Date("2021-10-01T00:00:00Z");
// 手动加上时区偏移(例如,东八区,+8小时)
const offsetHours = 8;
const localTime = new Date(utcDate.getTime() + offsetHours * 60 * 60 * 1000);
console.log("Local time with manual offset:", localTime.toString());

闰秒的处理方案

步进调整:传统解决方案

历史上,需要处理闰秒的系统常采用“步进调整”技术。该方法直接忽略闰秒,导致系统时钟在闰秒发生时突然向前或向后跳跃一秒。

例如下表所示:

UTC TAI POSIX时间步进对比表
图4:UTC、TAI与POSIX(步进)时间对应关系表

从表中可见,TAI和UTC时间都是严格单调递增的,但POSIX(步进)时间在闰秒处会发生跳跃。这导致两个不同的UTC时刻可能映射到同一个POSIX时间戳,从而引发问题。

假设在23:59:59.600发起付款请求,并在下一秒23:59:60.200批准。在步进调整的系统中,日志可能显示:

  • 315619199.600 - 请求付款
  • 315619199.200 - 已批准付款(时间戳反而更早)

这种时间“倒流”现象正是大多数现代系统寻求其他解决方案的原因。

闰秒涂抹:谷歌的平滑方案

在许多系统中,采用称为“闰秒涂抹”的技术来处理闰秒。其核心思想不是突然增加或减少一整秒,而是将这一秒的偏差均匀分摊到更长的时间段(例如24小时)内。

  • 在涂抹期间,每一秒的时长会略微变长或变短,从而确保系统时间平稳过渡,避免跳跃。
  • 与步进调整相比,涂抹能保证时钟严格递增,满足多数应用对单调时间的要求。

闰秒平滑处理示例表
图5:展示了步进调整与平滑涂抹处理闰秒的对比

上表中,POSIX(步进)完全忽略23:59:60这一秒。而POSIX(平滑)则通过微调每秒的时长,实现了时间的平稳过渡,代价是每秒的物理时长略有不同。这正是Google的NTP服务器处理闰秒的方式。

时间精确性对应用程序的影响

通常无需特别关注的情况

对于事件调度、计算年龄、或在用户界面中显示时间等常见任务,JavaScript基于POSIX的时间系统已足够精确。实践中,绝大多数时间相关错误实际上源于时区处理不当,而非秒长的微小差异。

需要特别关注的场景

然而,对于科学研究、高频交易、分布式系统同步等对时间精度要求极高的领域,由闰秒引起的微小差异可能导致严重后果。

精确的计时对于确保测量和交易的可靠性至关重要。在闰秒期间,单个POSIX时间戳可能对应UTC中的两个不同瞬间,这在需要严格时间同步的系统中会引入歧义和潜在错误。

希望本文能帮助你更深入地理解JavaScript中的时间系统。更多关于前端开发与网络协议的深度讨论,欢迎访问云栈社区进行交流。

参考资料




上一篇:GEO排名上去了却没询盘?别让错误认知阻碍AI搜索优化效果
下一篇:平台工程落地实战:Kubernetes + DevOps 团队转型路线图与内建开发者平台
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-11 08:35 , Processed in 0.198458 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表