Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 57 additions & 54 deletions Doc/includes/tzinfo_examples.py
Original file line number Diff line number Diff line change
@@ -1,68 +1,70 @@
from datetime import tzinfo, timedelta, datetime

ZERO = timedelta(0)
HOUR = timedelta(hours=1)
SECOND = timedelta(seconds=1)
import datetime as dt

# A class capturing the platform's idea of local time.
# (May result in wrong values on historical times in
# timezones where UTC offset and/or the DST rules had
# changed in the past.)
import time as _time

STDOFFSET = timedelta(seconds = -_time.timezone)
ZERO = dt.timedelta(0)
HOUR = dt.timedelta(hours=1)
SECOND = dt.timedelta(seconds=1)

STDOFFSET = dt.timedelta(seconds=-_time.timezone)
if _time.daylight:
DSTOFFSET = timedelta(seconds = -_time.altzone)
DSTOFFSET = dt.timedelta(seconds=-_time.altzone)
else:
DSTOFFSET = STDOFFSET

DSTDIFF = DSTOFFSET - STDOFFSET

class LocalTimezone(tzinfo):

def fromutc(self, dt):
class LocalTimezone(dt.tzinfo):

def fromutc(self, when):
assert dt.tzinfo is self
stamp = (dt - datetime(1970, 1, 1, tzinfo=self)) // SECOND
stamp = (when - dt.datetime(1970, 1, 1, tzinfo=self)) // SECOND
args = _time.localtime(stamp)[:6]
dst_diff = DSTDIFF // SECOND
# Detect fold
fold = (args == _time.localtime(stamp - dst_diff))
return datetime(*args, microsecond=dt.microsecond,
tzinfo=self, fold=fold)
return dt.datetime(*args, microsecond=when.microsecond,
tzinfo=self, fold=fold)

def utcoffset(self, dt):
if self._isdst(dt):
def utcoffset(self, when):
if self._isdst(when):
return DSTOFFSET
else:
return STDOFFSET

def dst(self, dt):
if self._isdst(dt):
def dst(self, when):
if self._isdst(when):
return DSTDIFF
else:
return ZERO

def tzname(self, dt):
return _time.tzname[self._isdst(dt)]
def tzname(self, when):
return _time.tzname[self._isdst(when)]

def _isdst(self, dt):
tt = (dt.year, dt.month, dt.day,
dt.hour, dt.minute, dt.second,
dt.weekday(), 0, 0)
def _isdst(self, when):
tt = (when.year, when.month, when.day,
when.hour, when.minute, when.second,
when.weekday(), 0, 0)
stamp = _time.mktime(tt)
tt = _time.localtime(stamp)
return tt.tm_isdst > 0


Local = LocalTimezone()


# A complete implementation of current DST rules for major US time zones.

def first_sunday_on_or_after(dt):
days_to_go = 6 - dt.weekday()
def first_sunday_on_or_after(when):
days_to_go = 6 - when.weekday()
if days_to_go:
dt += timedelta(days_to_go)
return dt
when += dt.timedelta(days_to_go)
return when


# US DST Rules
Expand All @@ -75,21 +77,22 @@ def first_sunday_on_or_after(dt):
#
# In the US, since 2007, DST starts at 2am (standard time) on the second
# Sunday in March, which is the first Sunday on or after Mar 8.
DSTSTART_2007 = datetime(1, 3, 8, 2)
DSTSTART_2007 = dt.datetime(1, 3, 8, 2)
# and ends at 2am (DST time) on the first Sunday of Nov.
DSTEND_2007 = datetime(1, 11, 1, 2)
DSTEND_2007 = dt.datetime(1, 11, 1, 2)
# From 1987 to 2006, DST used to start at 2am (standard time) on the first
# Sunday in April and to end at 2am (DST time) on the last
# Sunday of October, which is the first Sunday on or after Oct 25.
DSTSTART_1987_2006 = datetime(1, 4, 1, 2)
DSTEND_1987_2006 = datetime(1, 10, 25, 2)
DSTSTART_1987_2006 = dt.datetime(1, 4, 1, 2)
DSTEND_1987_2006 = dt.datetime(1, 10, 25, 2)
# From 1967 to 1986, DST used to start at 2am (standard time) on the last
# Sunday in April (the one on or after April 24) and to end at 2am (DST time)
# on the last Sunday of October, which is the first Sunday
# on or after Oct 25.
DSTSTART_1967_1986 = datetime(1, 4, 24, 2)
DSTSTART_1967_1986 = dt.datetime(1, 4, 24, 2)
DSTEND_1967_1986 = DSTEND_1987_2006


def us_dst_range(year):
# Find start and end times for US DST. For years before 1967, return
# start = end for no DST.
Expand All @@ -100,63 +103,63 @@ def us_dst_range(year):
elif 1966 < year < 1987:
dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986
else:
return (datetime(year, 1, 1), ) * 2
return (dt.datetime(year, 1, 1), ) * 2

start = first_sunday_on_or_after(dststart.replace(year=year))
end = first_sunday_on_or_after(dstend.replace(year=year))
return start, end


class USTimeZone(tzinfo):
class USTimeZone(dt.tzinfo):

def __init__(self, hours, reprname, stdname, dstname):
self.stdoffset = timedelta(hours=hours)
self.stdoffset = dt.timedelta(hours=hours)
self.reprname = reprname
self.stdname = stdname
self.dstname = dstname

def __repr__(self):
return self.reprname

def tzname(self, dt):
if self.dst(dt):
def tzname(self, when):
if self.dst(when):
return self.dstname
else:
return self.stdname

def utcoffset(self, dt):
return self.stdoffset + self.dst(dt)
def utcoffset(self, when):
return self.stdoffset + self.dst(when)

def dst(self, dt):
if dt is None or dt.tzinfo is None:
def dst(self, when):
if when is None or when.tzinfo is None:
# An exception may be sensible here, in one or both cases.
# It depends on how you want to treat them. The default
# fromutc() implementation (called by the default astimezone()
# implementation) passes a datetime with dt.tzinfo is self.
# implementation) passes a datetime with when.tzinfo is self.
return ZERO
assert dt.tzinfo is self
start, end = us_dst_range(dt.year)
assert when.tzinfo is self
start, end = us_dst_range(when.year)
# Can't compare naive to aware objects, so strip the timezone from
# dt first.
dt = dt.replace(tzinfo=None)
# when first.
when = when.replace(tzinfo=None)
if start + HOUR <= dt < end - HOUR:
# DST is in effect.
return HOUR
if end - HOUR <= dt < end:
# Fold (an ambiguous hour): use dt.fold to disambiguate.
return ZERO if dt.fold else HOUR
if start <= dt < start + HOUR:
if end - HOUR <= when < end:
# Fold (an ambiguous hour): use when.fold to disambiguate.
return ZERO if when.fold else HOUR
if start <= when < start + HOUR:
# Gap (a non-existent hour): reverse the fold rule.
return HOUR if dt.fold else ZERO
return HOUR if when.fold else ZERO
# DST is off.
return ZERO

def fromutc(self, dt):
assert dt.tzinfo is self
start, end = us_dst_range(dt.year)
def fromutc(self, when):
assert when.tzinfo is self
start, end = us_dst_range(when.year)
start = start.replace(tzinfo=self)
end = end.replace(tzinfo=self)
std_time = dt + self.stdoffset
std_time = when + self.stdoffset
dst_time = std_time + HOUR
if end <= dst_time < end + HOUR:
# Repeated hour
Expand Down
Loading
Loading