import time
from datetime import tzinfo, timedelta, datetime
ZERO_HR = timedelta(hours=0)
ONE_HR = timedelta(hours=1)
class UTCTimeZone(tzinfo):
def __init__(self, minutes=0, dst=False, tzname=""):
self.__minutes = minutes
self.__dst = dst
self.__tzname = tzname
def utcoffset(self, dt):
if self.__dst:
return timedelta(minutes=self.__minutes) + self.dst(dt)
return timedelta(minutes=self.__minutes)
def tzname(self, dt):
if self.__tzname:
return self.__tzname
dst_str = " DST" if self.__dst else ""
if self.__minutes == 0:
return "UTC" + dst_str
mm = self.__minutes
sign = "+"
if mm < 0:
mm *= -1
sign = "-"
hh = mm / 60
mm %= 60
return "UTC %(sign)s%(hours)02d%(minutes)02d%(dst)s" % {"sign":sign, "hours":hh,
"minutes":mm, "dst":dst_str}
def _FirstSunday(self, dt):
"""First Sunday on or after dt."""
return dt + timedelta(days=(6-dt.weekday()))
def dst(self, dt):
if self.__dst:
# 2am on the 2nd Sunday in Mar
dst_start = self._FirstSunday(datetime(dt.year, 3, 8, 2))
# 1am on the 1st Sunday in Nov
dst_end = self._FirstSunday(datetime(dt.year, 11, 1, 1))
return ONE_HR if dst_start <= dt.replace(tzinfo=None) < dst_end else ZERO_HR
return ZERO_HR
aW1wb3J0IHRpbWUKZnJvbSBkYXRldGltZSBpbXBvcnQgdHppbmZvLCB0aW1lZGVsdGEsIGRhdGV0aW1lCgpaRVJPX0hSID0gdGltZWRlbHRhKGhvdXJzPTApCk9ORV9IUiA9IHRpbWVkZWx0YShob3Vycz0xKQoKY2xhc3MgVVRDVGltZVpvbmUodHppbmZvKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBtaW51dGVzPTAsIGRzdD1GYWxzZSwgdHpuYW1lPSIiKToKICAgICAgICBzZWxmLl9fbWludXRlcyA9IG1pbnV0ZXMKICAgICAgICBzZWxmLl9fZHN0ID0gZHN0CiAgICAgICAgc2VsZi5fX3R6bmFtZSA9IHR6bmFtZQoKICAgIGRlZiB1dGNvZmZzZXQoc2VsZiwgZHQpOgogICAgICAgIGlmIHNlbGYuX19kc3Q6CiAgICAgICAgICAgIHJldHVybiB0aW1lZGVsdGEobWludXRlcz1zZWxmLl9fbWludXRlcykgKyBzZWxmLmRzdChkdCkKICAgICAgICByZXR1cm4gdGltZWRlbHRhKG1pbnV0ZXM9c2VsZi5fX21pbnV0ZXMpCgogICAgZGVmIHR6bmFtZShzZWxmLCBkdCk6CiAgICAgICAgaWYgc2VsZi5fX3R6bmFtZToKICAgICAgICAgICAgcmV0dXJuIHNlbGYuX190em5hbWUKICAgICAgICBkc3Rfc3RyID0gIiBEU1QiIGlmIHNlbGYuX19kc3QgZWxzZSAiIgogICAgICAgIGlmIHNlbGYuX19taW51dGVzID09IDA6CiAgICAgICAgICAgIHJldHVybiAiVVRDIiArIGRzdF9zdHIKICAgICAgICBtbSA9IHNlbGYuX19taW51dGVzCiAgICAgICAgc2lnbiA9ICIrIgogICAgICAgIGlmIG1tIDwgMDoKICAgICAgICAgICAgbW0gKj0gLTEKICAgICAgICAgICAgc2lnbiA9ICItIgogICAgICAgIGhoID0gbW0gLyA2MAogICAgICAgIG1tICU9IDYwCiAgICAgICAgcmV0dXJuICJVVEMgJShzaWduKXMlKGhvdXJzKTAyZCUobWludXRlcykwMmQlKGRzdClzIiAlIHsic2lnbiI6c2lnbiwgImhvdXJzIjpoaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtaW51dGVzIjptbSwgImRzdCI6ZHN0X3N0cn0KCiAgICBkZWYgX0ZpcnN0U3VuZGF5KHNlbGYsIGR0KToKICAgICAgICAiIiJGaXJzdCBTdW5kYXkgb24gb3IgYWZ0ZXIgZHQuIiIiCiAgICAgICAgcmV0dXJuIGR0ICsgdGltZWRlbHRhKGRheXM9KDYtZHQud2Vla2RheSgpKSkKCiAgICBkZWYgZHN0KHNlbGYsIGR0KToKICAgICAgICBpZiBzZWxmLl9fZHN0OgogICAgICAgICAgICAjIDJhbSBvbiB0aGUgMm5kIFN1bmRheSBpbiBNYXIKICAgICAgICAgICAgZHN0X3N0YXJ0ID0gc2VsZi5fRmlyc3RTdW5kYXkoZGF0ZXRpbWUoZHQueWVhciwgMywgOCwgMikpCiAgICAgICAgICAgICMgMWFtIG9uIHRoZSAxc3QgU3VuZGF5IGluIE5vdgogICAgICAgICAgICBkc3RfZW5kID0gc2VsZi5fRmlyc3RTdW5kYXkoZGF0ZXRpbWUoZHQueWVhciwgMTEsIDEsIDEpKQogICAgICAgICAgICByZXR1cm4gT05FX0hSIGlmIGRzdF9zdGFydCA8PSBkdC5yZXBsYWNlKHR6aW5mbz1Ob25lKSA8IGRzdF9lbmQgZWxzZSBaRVJPX0hSCiAgICAgICAgcmV0dXJuIFpFUk9fSFI=