summaryrefslogtreecommitdiffstats
path: root/Tools/tz/zdump.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/tz/zdump.py')
-rw-r--r--Tools/tz/zdump.py81
1 files changed, 81 insertions, 0 deletions
diff --git a/Tools/tz/zdump.py b/Tools/tz/zdump.py
new file mode 100644
index 0000000..f94b483
--- /dev/null
+++ b/Tools/tz/zdump.py
@@ -0,0 +1,81 @@
+import sys
+import os
+import struct
+from array import array
+from collections import namedtuple
+from datetime import datetime, timedelta
+
+ttinfo = namedtuple('ttinfo', ['tt_gmtoff', 'tt_isdst', 'tt_abbrind'])
+
+class TZInfo:
+ def __init__(self, transitions, type_indices, ttis, abbrs):
+ self.transitions = transitions
+ self.type_indices = type_indices
+ self.ttis = ttis
+ self.abbrs = abbrs
+
+ @classmethod
+ def fromfile(cls, fileobj):
+ if fileobj.read(4).decode() != "TZif":
+ raise ValueError("not a zoneinfo file")
+ fileobj.seek(20)
+ header = fileobj.read(24)
+ tzh = (tzh_ttisgmtcnt, tzh_ttisstdcnt, tzh_leapcnt,
+ tzh_timecnt, tzh_typecnt, tzh_charcnt) = struct.unpack(">6l", header)
+ transitions = array('i')
+ transitions.fromfile(fileobj, tzh_timecnt)
+ if sys.byteorder != 'big':
+ transitions.byteswap()
+
+ type_indices = array('B')
+ type_indices.fromfile(fileobj, tzh_timecnt)
+
+ ttis = []
+ for i in range(tzh_typecnt):
+ ttis.append(ttinfo._make(struct.unpack(">lbb", fileobj.read(6))))
+
+ abbrs = fileobj.read(tzh_charcnt)
+
+ self = cls(transitions, type_indices, ttis, abbrs)
+ self.tzh = tzh
+
+ return self
+
+ def dump(self, stream, start=None, end=None):
+ for j, (trans, i) in enumerate(zip(self.transitions, self.type_indices)):
+ utc = datetime.utcfromtimestamp(trans)
+ tti = self.ttis[i]
+ lmt = datetime.utcfromtimestamp(trans + tti.tt_gmtoff)
+ abbrind = tti.tt_abbrind
+ abbr = self.abbrs[abbrind:self.abbrs.find(0, abbrind)].decode()
+ if j > 0:
+ prev_tti = self.ttis[self.type_indices[j - 1]]
+ shift = " %+g" % ((tti.tt_gmtoff - prev_tti.tt_gmtoff) / 3600)
+ else:
+ shift = ''
+ print("%s UTC = %s %-5s isdst=%d" % (utc, lmt, abbr, tti[1]) + shift, file=stream)
+
+ @classmethod
+ def zonelist(cls, zonedir='/usr/share/zoneinfo'):
+ zones = []
+ for root, _, files in os.walk(zonedir):
+ for f in files:
+ p = os.path.join(root, f)
+ with open(p, 'rb') as o:
+ magic = o.read(4)
+ if magic == b'TZif':
+ zones.append(p[len(zonedir) + 1:])
+ return zones
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ zones = TZInfo.zonelist()
+ for z in zones:
+ print(z)
+ sys.exit()
+ filepath = sys.argv[1]
+ if not filepath.startswith('/'):
+ filepath = os.path.join('/usr/share/zoneinfo', filepath)
+ with open(filepath, 'rb') as fileobj:
+ tzi = TZInfo.fromfile(fileobj)
+ tzi.dump(sys.stdout)