#!/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, stat __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 contasining 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: cfp = open(__cachepath) txt = cfp.read() cfp.close() (offset, valid_from) = map(int, txt.split()) if valid_from < last_insertion: 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 retrieve()