1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
#!/usr/bin/env python
# $Id$
#
# Get the current leap-second value. This is the offset between UTC and
# GPS time, which changes occasionally due to variations in the Earth's
# rotation.
#
import os, urllib, re, random, time, calendar
__locations = [
(
# U.S. Navy's offset-history file
"ftp://maia.usno.navy.mil/ser7/tai-utc.dat",
r" TAI-UTC= +([0-9-]+)[^\n]*\n$",
1,
19, # Magic TAI-GPS offset
),
(
# International Earth Rotation Service Bulletin C
"http://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat",
r" UTC-TAI = ([0-9-]+)",
-1,
19, # Magic TAI-GPS offset
),
]
# File containing cached offset data.
# Two fields: the offset, and the start of the current six-month span
# between times it might change, in seconds since Unix epoch GMT.
__cachepath = "/var/run/leapsecond"
def retrieve():
"Retrieve current leap-second from Web sources."
random.shuffle(__locations) # To spread the load
for (url, regexp, sign, offset) in __locations:
try:
ifp = urllib.urlopen(url)
txt = ifp.read()
ifp.close()
m = re.search(regexp, txt)
if m:
return int(m.group(1)) * sign - offset
except:
pass
else:
return None
def last_insertion_time():
"Give last potential insertion time for a leap second."
# We need the Unix times for midnights Jan 1 and Jul 1 this year.
when = time.gmtime()
when.tm_mday = 1
when.tm_hour = when.tm_min = when.tm_sec = 0
when.tm_mon = 1; jan = int(calendar.timegm(when))
when.tm_mon = 7; jul = int(calendar.timegm(when))
# We have the UTC times of the potential insertion points this year.
now = time()
if now > jul:
return jul
else:
return jan
def get():
"Fetch GPS offset, from local cache file if possible."
stale = False
last_insertion = last_insertion_time()
if not os.path.exists(__cachepath):
stale = True
else:
try:
cfp = open(__cachepath)
txt = cfp.read()
cfp.close()
(offset, valid_from) = map(int, txt.split())
if valid_from < last_insertion:
stale = True
except (IOError, OSError, ValueError):
stale = True
# We now know whether the cached data is stale
if not stale:
return offset
else:
current_offset = retrieve()
# Try to cache this for later
if current_offset != None:
try:
cfp = open(__cachepath, "w")
cfp.write("%d %d\n" % (offset, last_insertion))
cfp.close()
except (IOError, OSError):
pass
return current_offset
if __name__ == '__main__':
print "Current leap second:", retrieve()
|