有没有办法从分布在大多数 Linux 发行版上的时区数据库中提取历史闰秒时刻?我正在寻找 python 中的解决方案,但是在命令行上工作的任何东西都可以。
我的用例是在 gps 时间(基本上是自 1980 年第一颗 GPS 卫星开启以来的秒数)和 UTC 或本地时间之间进行转换。UTC 不时调整闰秒,而 gps-time 线性增加。这相当于在 UTC 和TAI之间转换之间进行转换。TAI 也忽略闰秒,因此 TAI 和 gps-time 应该始终以相同的偏移量演变。在工作中,我们使用 gps-time 作为全球同步天文观测的时间标准。
我有在 gps-time 和 UTC 之间转换的工作函数,但我必须硬编码一个闰秒表,我在这里得到了(该文件tzdata2013xx.tar.gz
包含一个名为leapseconds
)。每隔几年,当宣布新的闰秒时,我必须手动更新此文件。我更愿意从标准 tzdata 中获取此信息,该信息每年通过系统更新数次自动更新。
我很确定这些信息隐藏在 /usr/share/zoneinfo/
. 我已经能够使用struct.unpack
(man tzfile
给出一些关于格式的信息)来提取其中的一些,但我从来没有让它完全工作。是否有任何标准软件包可以访问此信息?我知道pytz,它似乎从同一个数据库中获取标准 DST 信息,但它不能访问闰秒。我还找到了 tai64n,但查看它的源代码,它只包含一个硬编码表。
编辑
受到 steveha 的回答和pytz/tzfile.py中的一些代码的启发,我终于得到了一个可行的解决方案(在 py2.5 和 py2.7 上测试):
from struct import unpack, calcsize
from datetime import datetime
def print_leap(tzfile = '/usr/share/zoneinfo/right/UTC'):
with open(tzfile, 'rb') as f:
# read header
fmt = '>4s c 15x 6l'
(magic, format, ttisgmtcnt, ttisstdcnt,leapcnt, timecnt,
typecnt, charcnt) = unpack(fmt, f.read(calcsize(fmt)))
assert magic == 'TZif'.encode('US-ASCII'), 'Not a timezone file'
print 'Found %i leapseconds:' % leapcnt
# skip over some uninteresting data
fmt = '>%(timecnt)dl %(timecnt)dB %(ttinfo)s %(charcnt)ds' % dict(
timecnt=timecnt, ttinfo='lBB'*typecnt, charcnt=charcnt)
f.read(calcsize(fmt))
#read leap-seconds
fmt = '>2l'
for i in xrange(leapcnt):
tleap, nleap = unpack(fmt, f.read(calcsize(fmt)))
print datetime.utcfromtimestamp(tleap-nleap+1)
结果
In [2]: print_leap()
Found 25 leapseconds:
1972-07-01 00:00:00
1973-01-01 00:00:00
1974-01-01 00:00:00
...
2006-01-01 00:00:00
2009-01-01 00:00:00
2012-07-01 00:00:00
虽然这确实解决了我的问题,但我可能不会选择这个解决方案。相反,我将按照 Matt Johnson 的建议在我的代码中包含leap-seconds.list 。这似乎是用作 tzdata 来源的权威列表,并且可能每年由 NIST 更新两次。这意味着我将不得不手动进行更新,但是这个文件很容易解析并且包含一个过期日期(似乎缺少 tzdata)。