Extract historic leap seconds from tzdata

后端 未结 2 1031
轻奢々
轻奢々 2020-12-15 18:34

Is there a way to extract the moment of historic leap seconds from the time-zone database that is distributed on most linux distributions? I am looking for a solution in pyt

相关标签:
2条回答
  • 2020-12-15 19:33

    PyEphem has a delta_t function which returns the difference between Terrestrial Time and Universal Time (seconds). You can subtract 32.184 from it to get Leap Seconds (ref).

    import ephem, datetime
    ephem.delta_t(datetime.datetime.now()) - 32.184
    Out[2]: 35.01972996360122
    
    0 讨论(0)
  • 2020-12-15 19:34

    I just did man 5 tzfile and computed an offset that would find the leap seconds info, then read the leap seconds info.

    You can uncomment the "DEBUG:" print statements to see more of what it finds in the file.

    EDIT: program updated to now be correct. It now uses the file /usr/share/zoneinfo/right/UTC and it now finds leap-seconds to print.

    The original program wasn't skipping the timezeone abbreviation characters, which are documented in the man page but sort of hidden ("...and tt_abbrind serves as an index into the array of timezone abbreviation characters that follow the ttinfo structure(s) in the file.").

    import datetime
    import struct
    
    TZFILE_MAGIC = 'TZif'.encode('US-ASCII')
    
    def leap_seconds(f):
        """
        Return a list of tuples of this format: (timestamp, number_of_seconds)
            timestamp: a 32-bit timestamp, seconds since the UNIX epoch
            number_of_seconds: how many leap-seconds occur at timestamp
    
        """
        fmt = ">4s c 15x 6l"
        size = struct.calcsize(fmt)
        (tzfile_magic, tzfile_format, ttisgmtcnt, ttisstdcnt, leapcnt, timecnt,
            typecnt, charcnt) =  struct.unpack(fmt, f.read(size))
        #print("DEBUG: tzfile_magic: {} tzfile_format: {} ttisgmtcnt: {} ttisstdcnt: {} leapcnt: {} timecnt: {} typecnt: {} charcnt: {}".format(tzfile_magic, tzfile_format, ttisgmtcnt, ttisstdcnt, leapcnt, timecnt, typecnt, charcnt))
    
        # Make sure it is a tzfile(5) file
        assert tzfile_magic == TZFILE_MAGIC, (
                "Not a tzfile; file magic was: '{}'".format(tzfile_magic))
    
        # comments below show struct codes such as "l" for 32-bit long integer
        offset = (timecnt*4  # transition times, each "l"
            + timecnt*1  # indices tying transition time to ttinfo values, each "B"
            + typecnt*6  # ttinfo structs, each stored as "lBB"
            + charcnt*1)  # timezone abbreviation chars, each "c"
    
        f.seek(offset, 1) # seek offset bytes from current position
    
        fmt = '>{}l'.format(leapcnt*2)
        #print("DEBUG: leapcnt: {}  fmt: '{}'".format(leapcnt, fmt))
        size = struct.calcsize(fmt)
        data = struct.unpack(fmt, f.read(size))
    
        lst = [(data[i], data[i+1]) for i in range(0, len(data), 2)]
        assert all(lst[i][0] < lst[i+1][0] for i in range(len(lst)-1))
        assert all(lst[i][1] == lst[i+1][1]-1 for i in range(len(lst)-1))
    
        return lst
    
    def print_leaps(leap_lst):
        # leap_lst is tuples: (timestamp, num_leap_seconds)
        for ts, num_secs in leap_lst:
            print(datetime.datetime.utcfromtimestamp(ts - num_secs+1))
    
    if __name__ == '__main__':
        import os
        zoneinfo_fname = '/usr/share/zoneinfo/right/UTC'
        with open(zoneinfo_fname, 'rb') as f:
            leap_lst = leap_seconds(f)
        print_leaps(leap_lst)
    
    0 讨论(0)
提交回复
热议问题