1、GMT (Greenwich Mean Time,格林尼治标准时间)
- GMT 是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间。
- GMT 的正午时间:
- 是指当太阳横穿格林尼治子午线时(即:在格林尼治上空最高点时)的时间。
- 由于地球在它的椭圆轨道里的运动速度不均匀 。
- 时刻:可能与实际的太阳时有误差,最大误差达 16 分钟。
- 由于地球每天的自转是有些不规则的,而且正在缓慢减速。
- 现在的标准时间,是由原子钟报时的 协调世界时(UTC) 。
2、UTC (Coordinated Universal Time,协调世界时 / 世界标准时间)
- 1967 年国际度量衡大会决定,以铯原子 跃迁 9192631770 个周期,所持续的时间长度 定义为 1 秒!
- 科研技术还在发展,精密设备和测量能力也越来越高,最新的原子钟甚至可以达到 1 亿年不差 1 秒!
- 有了原子钟,人们基于原子钟又确立了一套新的时间标准,叫做「国际原子时」(International Atomic Time,简称 TAI)。
- UTC 是基于原子钟(国际原子时,TAI)的全球统一时间标准,通过插入 闰秒 调整以对齐地球自转。
- 时间差:
- TAI 与 UTC 的差值为整数秒,且每次 UTC 添加 闰秒 时,TAI 比 UTC 提前 1 秒。
- 截至 2024 年 1 月,TAI = UTC + 37 秒。
3、CST 时间
- CST 可以为如下 4 个不同的时区的缩写:
- 中国标准时间(北京时间):China Standard Time UTC+8(无夏令时)。
- 在时区划分上,属东八区,比协调世界时(UTC)早 8 小时 。
- 古巴标准时间:Cuba Standard Time UTC-4
- 美国中部时间:Central Standard Time (USA) UTC-6
- 澳大利亚中部时间:Central Standard Time (Australia) UTC+9:30
- 注意:编程中需明确时区代码(如:Asia/Shanghai 代替 CST 避免歧义)。
- 如:MySQL 的链接地址后边,跟上此参数(serverTimezone=Asia/Shanghai)。
url: jdbc:mysql://127.0.0.1:3306/smart?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
4、CET(Central European Time,欧洲中部时间)
- 欧洲中部时间 是比 世界标准时间(UTC)早一个小时的时区名称之一。
- 冬季时间为 UTC+1,夏季欧洲夏令时为 UTC+2。
5、ISO 时间(ISO 8601 标准时间格式)
- 国际标准化组织(ISO)制定的日期时间表示格式。
- 格式示例:
- 完整格式:2023-10-05T14:30:45+08:00(日期 + 时间 + 时区偏移)。
- 简化格式:20231005T143045+0800(无分隔符)。
- 特点:
- 明确、无歧义,支持排序和解析。
- 默认使用 UTC(如 2023-10-05T06:30:45Z,Z 表示 UTC)。
6、时间戳(Timestamp)
- 定义:从固定起点(Epoch)开始的时间偏移量,通常为整数或浮点数。
- 常见类型:
- Unix 时间戳:秒数(自 1970-01-01T00:00:00 UTC)。
- 毫秒级 时间戳:Java、JavaScript 常用(如:1696500000000)。
- 纳秒级 时间戳:高性能计算场景(如:1696500000000000000)。
- 应用场景:日志排序、缓存过期、分布式系统事件追踪。
7、NTP(Network Time Protocol,网络时间协议)
- 定义:用于同步 计算机系统时间的协议,基于分层 时钟源(Stratum)。
- 工作原理:
- 客户端向服务器发送时间查询请求,计算网络延迟并校准。
- 支持误差补偿(精度可达毫秒级)。
- 分层结构:
- Stratum 0:原子钟、GPS 时钟。
- Stratum 1:直接连接 Stratum 0 的服务器。
- Stratum 2:从 Stratum 1 同步的服务器(依此类推)。
- 应用场景:服务器集群、金融交易系统、工业控制系统。
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.8.0</version>
</dependency>
import org.apache.commons.net.ntp.NTPUDPClient;
import org.apache.commons.net.ntp.TimeInfo;
import java.net.InetAddress;
public class NTPTimeSync {
public static void main(String[] args) {
String ntpServer = "pool.ntp.org";
try {
NTPUDPClient client = new NTPUDPClient();
client.open();
InetAddress inetAddress = InetAddress.getByName(ntpServer);
TimeInfo timeInfo = client.getTime(inetAddress);
long returnTime = timeInfo.getMessage().getTransmitTimeStamp().getTime();
long localTime = System.currentTimeMillis();
long offset = returnTime - localTime;
long adjustedTime = System.currentTimeMillis() + offset;
System.out.println("校准前本地时间: " + localTime);
System.out.println("校准后本地时间: " + adjustedTime);
client.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
8、时间为什么会越走越不准?
- 钟表和计算机内部都有一个叫做「晶体振荡器」的东西,给它加上电压,它就会以固定的频率振动。
- 这个振动频率的「稳定性」,取决于它的制造工艺,以及外界环境的影响 。
- 出于成本的考虑,钟表的制作工艺没那么高。
- 电脑制造工艺虽然比较高。
- 但它内部的晶体振荡器也会受到「温度」变化带来的影响,在工作过程中,也会有产生误差 。
- 虽然它们的误差很小,但日积月累下来,误差就越来越明显。
9、Unix 2038 bug(Jason hatchet bug)
- 很多编程语言起源于 UNIX 系统,而 UNIX 系统认为 1970 年 1 月 1 日 0 点是时间纪元。
- 所以, UNIX 时间戳是以 1970 年 1 月 1 日 0 点为 计时起点时间 的。
- 最初计算机操作系统是 32 位,而时间也是用 32 位表示。
* Integer 在 JAVA 中用 32 位表示,因此,32 位能表示的最大值是 2147483647。
System.out.println(Integer.MAX_VALUE);
- 1 年 365 天的总秒数是 31536000 。
- 因此, 2147483647/31536000 = 68.1,32 位能表示的最长时间是 68 年。
- 1970 加上 68.1,实际最终到 2038 年 01 月 19 日 03 时 14 分 07 秒,便会到达最大时间。
- 这是著名的 Unix 2038 bug(Jason hatchet bug)。
- 过了这个时间点,所有 32 位操作系统时间便会变为 10000000 00000000 00000000 00000000,
- 算下来就是 1901 年 12 月 13 日 20 时 45 分 52 秒,便会出现 时间回归现象。
- 解决方案就是,计算机表示时间使用了 64 位来代替 32 位。
- 在 64 位系统下,此时间最多可以表示到 292,277,026,596 年 12 月 4 日 15 时 30 分 08 秒。这个时间就可以非常长了,在目前的人类生活时间中,远远够用了。
10、小结
- 存储与传输:
- 优先使用 UTC 时间和 ISO 8601 格式。
- 时区处理:
- 在展示时,转换为本地时间(如:ZonedDateTime in Java)。
- 同步机制:
- 关键系统部署 NTP 客户端,选择低 Stratum 服务器。
- 闰秒与 DST:
- 使用成熟时间库(如:java.time)自动处理复杂规则。