Appendix D. Leap Seconds (闰秒)
本附录详细说明闰秒的概念、历史和在RFC 3339中的处理方式。
什么是闰秒?
闰秒 (Leap Second) 是偶尔添加到协调世界时 (UTC) 中的一秒,用于使UTC时间与地球自转保持同步。
为什么需要闰秒?
原子时 (TAI):
- 基于原子钟,极其稳定
- 1秒 = 9,192,631,770个铯原子振荡周期
- 永不变化
地球自转:
- 不是完全均匀的
- 受潮汐摩擦等因素影响
- 逐渐变慢(每世纪约1.4毫秒/天)
- 速率不可预测
问题:
如果UTC仅基于原子时,几百年后UTC时间将与太阳时(地球自转)
显著偏离,最终可能在"中午"天还是黑的!
闰秒的运作方式
闰秒可以是正闰秒(添加一秒)或负闰秒(减少一秒),但到目前为止只添加过正闰秒。
正闰秒示例
正常的月末最后一分钟:
23:59:58
23:59:59
00:00:00 (下一天)
有正闰秒的月末:
23:59:58
23:59:59
23:59:60 ← 闰秒!
00:00:00 (下一天)
RFC 3339表示
1990-12-31T23:59:60Z ✅ 有效(1990年12月31日有闰秒)
2012-06-30T23:59:60Z ✅ 有效(2012年6月30日有闰秒)
2015-06-30T23:59:60Z ✅ 有效(2015年6月30日有闰秒)
2023-12-31T23:59:60Z ❌ 无效(2023年12月31日没有闰秒)
历史闰秒列表
自1972年引入UTC以来的所有闰秒:
年-月-日 UTC时间 TAI-UTC
1972-06-30 23:59:60Z +11秒
1972-12-31 23:59:60Z +12秒
1973-12-31 23:59:60Z +13秒
1974-12-31 23:59:60Z +14秒
1975-12-31 23:59:60Z +15秒
1976-12-31 23:59:60Z +16秒
1977-12-31 23:59:60Z +17秒
1978-12-31 23:59:60Z +18秒
1979-12-31 23:59:60Z +19秒
1981-06-30 23:59:60Z +20秒
1982-06-30 23:59:60Z +21秒
1983-06-30 23:59:60Z +22秒
1985-06-30 23:59:60Z +23秒
1987-12-31 23:59:60Z +24秒
1989-12-31 23:59:60Z +25秒
1990-12-31 23:59:60Z +26秒
1992-06-30 23:59:60Z +27秒
1993-06-30 23:59:60Z +28秒
1994-06-30 23:59:60Z +29秒
1995-12-31 23:59:60Z +30秒
1997-06-30 23:59:60Z +31秒
1998-12-31 23:59:60Z +32秒
2005-12-31 23:59:60Z +33秒
2008-12-31 23:59:60Z +34秒
2012-06-30 23:59:60Z +35秒
2015-06-30 23:59:60Z +36秒
2016-12-31 23:59:60Z +37秒
注意:
- 闰秒只在6月30日或12月31日添加
- 自1972年以来共添加了27个闰秒
- 最近的闰秒是2016年12月31日
- 闰秒的添加频率在减缓
编程中的闰秒处理
问题1: 大多数系统不支持闰秒
# Unix时间戳不表示闰秒
# 1990-12-31T23:59:59Z 和 1991-01-01T00:00:00Z
# 之间的时间戳相差1秒,而不是2秒
import time
from datetime import datetime
# 许多编程语言和操作系统会"抹平"闰秒
# 例如,在闰秒时刻,系统时钟可能会:
# 23:59:59 → 23:59:59 (停顿1秒) → 00:00:00
# 或者: 23:59:59 → 23:59:60 → 00:00:00
# 或者: 23:59:59 → 00:00:00 (跳过闰秒)
问题2: 解析23:59:60
# 标准库通常不支持60秒
from datetime import datetime
try:
dt = datetime(1990, 12, 31, 23, 59, 60)
# 大多数实现会抛出ValueError
except ValueError as e:
print(f"Error: {e}")
# 可能的解决方案:
dt = datetime(1990, 12, 31, 23, 59, 59)
# 或者:
dt = datetime(1991, 1, 1, 0, 0, 0)
宽容的解析实现
def parse_rfc3339_with_leap_seconds(timestamp_str):
"""
宽容地解析RFC 3339时间戳,包括闰秒
"""
# 检查是否包含闰秒
if ':60' in timestamp_str:
# 将60秒替换为59秒
timestamp_str = timestamp_str.replace(':60', ':59')
# 解析并添加1秒
dt = datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
return dt + timedelta(seconds=1)
else:
return datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
# 示例
ts1 = parse_rfc3339_with_leap_seconds("1990-12-31T23:59:60Z")
ts2 = parse_rfc3339_with_leap_seconds("1991-01-01T00:00:00Z")
print(ts1 == ts2) # True (它们表示相同的时间点)
RFC 3339的闰秒规范
语法要求
time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second rules
- 秒值 可以 (MAY) 是60
- 但仅在月末
- 且必须是已公布的闰秒
验证示例
# 已知的闰秒日期(需定期更新)
LEAP_SECONDS = {
(1990, 12, 31),
(1992, 6, 30),
(1993, 6, 30),
(1994, 6, 30),
(1995, 12, 31),
(1997, 6, 30),
(1998, 12, 31),
(2005, 12, 31),
(2008, 12, 31),
(2012, 6, 30),
(2015, 6, 30),
(2016, 12, 31),
# 未来的闰秒需要添加
}
def is_valid_leap_second(year, month, day, hour, minute, second):
"""验证闰秒是否有效"""
if second != 60:
return True # 不是闰秒,不需要特殊验证
# 闰秒只能出现在23:59:60
if hour != 23 or minute != 59:
return False
# 必须是月末
if (month, day) not in [(6, 30), (12, 31)]:
return False
# 必须是已公布的闰秒日期
return (year, month, day) in LEAP_SECONDS
获取最新闰秒信息
IERS公告
国际地球自转和参考系统服务 (IERS) 负责宣布闰秒:
官方网站: https://www.iers.org/
公告: Bulletin C
闰秒通常提前6个月宣布
NTP闰秒指示器
NTP (Network Time Protocol) 服务器在闰秒前24小时设置闰秒指示器:
# NTP客户端可以查询闰秒指示器
import ntplib
c = ntplib.NTPClient()
response = c.request('pool.ntp.org')
leap_indicator = response.leap
# 0: 无警告
# 1: 最后一分钟有61秒(正闰秒)
# 2: 最后一分钟有59秒(负闰秒)
# 3: 闹钟状态(时钟未同步)
闰秒的争议和未来
争议
支持者:
- 保持UTC与太阳时同步
- 避免天文观测混乱
反对者:
- 造成技术系统问题
- 无法预测(需提前6个月公布)
- 许多系统实现不正确
可能的未来变化
2022年决议:
国际电信联盟(ITU)投票决定在2035年或之后
停止闰秒的插入
可能的替代方案:
1. 每100年插入一次"闰小时"
2. 允许UTC与太阳时逐渐偏离
3. 重新定义UTC
实施建议
1. 宽容地接受
# 接受60秒,但转换为标准表示
def normalize_leap_second(dt_str):
if ':60' in dt_str:
# 将23:59:60转换为下一天的00:00:00
# 或保留为23:59:59 + note
pass
2. 使用UTC
# 始终使用UTC进行内部存储
# 避免本地时区的复杂性
from datetime import timezone
dt = datetime.now(timezone.utc)
3. 测试边界情况
# 测试闰秒的前后时刻
test_cases = [
"1990-12-31T23:59:59Z",
"1990-12-31T23:59:60Z", # 闰秒
"1991-01-01T00:00:00Z",
]
4. 监控IERS公告
定期检查https://www.iers.org/ 获取闰秒公告。
关键要点: 闰秒是UTC时间系统的一个复杂特性。虽然RFC 3339语法上支持闰秒,但大多数系统实现会遇到困难。实现应宽容地处理闰秒,并保持与权威时间源(如NTP)的同步。