# Author: Ted Horst # TZDIR hacks by Keith Waclena # http://www.lib.uchicago.edu/keith/ import os # FreeBSD and Linux don't have the same ones... *sigh* AlternateMap = { "US/Pacific": "PST8PDT", "US/Mountain": "MST7MDT", "US/Central": "CST6CDT", "US/Eastern": "EST5EDT", "US/Hawaii": "Pacific/Honolulu", "US/Samoa": "Pacific/Pago_Pago", "US/Arizona": "America/Phoenix", "Canada/Saskatchewan": "America/Regina", "US/East-Indiana": "America/Indianapolis", "Canada/Atlantic": "America/Caracas", "Canada/Newfoundland": "America/St_Johns", "UTC": "GMT", } candidates = ['/usr/share/zoneinfo/', '/etc/zoneinfo/', '/usr/share/lib/zoneinfo/'] if os.environ.has_key('TZDIR'): TZDIR = os.environ['TZDIR'] else: TZDIR = None for d in candidates: if os.path.isdir(d): TZDIR = d break if not TZDIR: raise IOError, (2, 'No such file or directory') del d if os.environ.has_key('TZDEFAULT'): TZDEFAULT = os.environ['TZDEFAULT'] elif os.environ.has_key('TZ'): TZDEFAULT = os.environ['TZ'] else: TZDEFAULT = '/etc/localtime' RESERVED = 32 zoneCache = {} Error = "Zone Error" def zone(name = ''): if not name: name = TZDEFAULT if not zoneCache.has_key(name): zoneCache[name] = Zone(name) return zoneCache[name] class Zone: def __init__(self, name = ''): import xdrlib if not name: name = TZDEFAULT if name[:6] == 'India/': # fix alanb bug name = 'Indian/' + name[6:] self.name = name possible = [] possible.append (name) if AlternateMap.has_key(name): possible.append (AlternateMap[name]) possible.append ('UTC') possible.append ('GMT') fd = None for zone_name in possible: try: fd = open(os.path.join(TZDIR, zone_name), 'rb') break except IOError, reason: fd = None if fd is None: raise Error, "Unable to find Zone data for %s" % name tz = fd.read() fd.close() pos = RESERVED up = xdrlib.Unpacker(tz[pos:pos + 12]) pos = pos + 12 self.tzh_timecnt = up.unpack_int() self.tzh_typecnt = up.unpack_int() self.tzh_charcnt = up.unpack_int() up.reset(tz[pos:pos + 4*self.tzh_timecnt]) pos = pos + 4*self.tzh_timecnt self.transition_times = [] for i in range(self.tzh_timecnt): self.transition_times.append(up.unpack_int()) self.type_indexes = tz[pos:pos + self.tzh_timecnt] pos = pos + self.tzh_timecnt data = tz[pos:pos + 6*self.tzh_typecnt] self.ttinfos = [] for i in range(self.tzh_typecnt): up.reset(data[6*i:6*i + 4]) self.ttinfos.append((up.unpack_int(), ord(data[6*i + 4]), ord(data[6*i + 5]))) pos = pos + 6*self.tzh_typecnt allzones = tz[pos:pos + self.tzh_charcnt] self.zonelist = ['']*len(allzones) place = 0 for i in range(len(allzones)): if allzones[i] == '\000': self.zonelist[place] = allzones[place:i] place = i + 1 def default_index(self): if self.tzh_timecnt == 0: return 0 for i in range(self.tzh_typecnt): if self.ttinfos[i][1] == 0: return i return 0 def index(self, when = None): t_t = self.transition_times if when is None: import time when = time.time() if self.tzh_timecnt == 0: ind = (0, 0, 0) elif when < t_t[0]: i = self.default_index() ind = (i, ord(self.type_indexes[0]), i) elif when >= t_t[-1]: if self.tzh_timecnt > 1: ind = (ord(self.type_indexes[-1]), ord(self.type_indexes[-1]), ord(self.type_indexes[-2])) else: ind = (ord(self.type_indexes[-1]), ord(self.type_indexes[-1]), self.default_index()) else: for i in range(self.tzh_timecnt - 1): if when < t_t[i + 1]: if i == 0: ind = (ord(self.type_indexes[0]), ord(self.type_indexes[1]), self.default_index()) else: ind = (ord(self.type_indexes[i]), ord(self.type_indexes[i + 1]), ord(self.type_indexes[i - 1])) break return ind def info(self, when = None): try: ttind = self.ttinfos[self.index(when)[0]] return ttind[0], ttind[1], self.zonelist[ttind[2]] except: import handle_error handle_error.HandleException("Zone error: %s %s %s %s" % (self.name, when, self.ttinfos, self.zonelist)) def from_time(self, otime): for i in self.index(otime): ftime = otime - self.ttinfos[i][0] if otime == ftime + self.info(ftime)[0]: break return ftime def to_time(self, otime): for i in self.index(otime): ftime = otime + self.ttinfos[i][0] if otime == ftime - self.info(ftime)[0]: break return ftime def zones(self): return filter(None, self.zonelist) def _nest_list(list, prefix, zdir): import os lv = os.listdir(zdir) for a in lv: if os.path.isfile(zdir + a): list.append(prefix + a) elif os.path.isdir(zdir + a) and a != os.curdir and a != os.pardir: _nest_list(list, prefix + a + os.sep, zdir + a + os.sep) def zone_names(): zs = [] _nest_list(zs, '', TZDIR) return zs