[Python-checkins] python/nondist/sandbox/datetime EU.py,NONE,1.1
gvanrossum@users.sourceforge.net
gvanrossum@users.sourceforge.net
Fri, 27 Dec 2002 19:53:55 -0800
Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory sc8-pr-cvs1:/tmp/cvs-serv5442
Added Files:
EU.py
Log Message:
A tzinfo object implementing the European DST rules.
--- NEW FILE: EU.py ---
"""A tzinfo object implementing the European DST rules.
See http://webexhibits.org/daylightsaving/g.html
Start: last Sunday in March at 1am UTC
End: last Sunday in October at 1am UTC
Note the subtle difference with the US: all European countries switch
to and from DST *at the same instant*, where in the US states in
different timezones switch at the same local time, which means that
while Eastern time is already on DST, Pacific time will be on normal
time three more hours. (These are the EU rules; Russia switches at
2am local time.) Another difference with the US is that the US
switches on the first Sunday in April. Cuba switches on April
1st. :-) All switch back on the same date.
"""
from datetime import date, time, timedelta, datetime, datetimetz, tzinfo
def last_sunday_in(year, month):
assert month in [3, 10] # This only works for 31-day months!
d = date(year, month, 31)
w = d.weekday() # Mon = 0, Sun = 6
if w != 6:
d -= timedelta(days=w+1)
return d
DAY = timedelta(days=1)
HOUR = timedelta(hours=1)
ZERO = timedelta()
ONE_AM = time(1)
class Fixed(tzinfo):
def __init__(self, offset, name):
self.offset = offset
self.name = name
def tzname(self, dt):
return self.name
def utcoffset(self, dt):
return self.offset
def dst(self, dt):
return ZERO
class Europe(tzinfo):
def __init__(self, offset, stdname, dstname):
self.offset = offset
self.stdname = stdname
self.dstname = dstname
def tzname(self, dt):
if self.dst(dt):
return self.dstname
else:
return self.stdname
def utcoffset(self, dt):
return self.offset + self.dst(dt)
def dst(self, dt):
dston = last_sunday_in(dt.year, 3)
dstoff = last_sunday_in(dt.year, 10)
d = dt.date()
# Get a quick result on dates not near a DST switch:
if dston < d < dstoff - DAY:
return HOUR
if d < dston - DAY or dstoff < d:
return ZERO
# Need to be more careful in edge cases:
dston = datetime.combine(dston, ONE_AM)
dstoff = datetime.combine(dstoff, ONE_AM)
if dt.tzinfo is self:
# Can use self.offset
d = datetime.combine(dt.date(), dt.time()) - self.offset
else:
# Can call dt.tzoffset() without risking recursion
d = datetime.combine(dt.date(), dt.time()) - dt.utcoffset()
if dston <= d < dstoff:
return HOUR
else:
return ZERO
UTC = Fixed(ZERO, "UTC")
London = Europe(ZERO, "WET", "WDT")
Amsterdam = Europe(HOUR, "MET", "MDT")
demo = """
We start easy, Saturday noon in Amsterdam on the last day of DST:
>>> dt = datetimetz(2002, 10, 26, 12, 0, 0, tzinfo=Amsterdam)
>>> dt.ctime()
'Sat Oct 26 12:00:00 2002'
The UTC offset is 2 hours:
>>> dt.utcoffset().seconds
7200
Now add one day, getting Sunday noon on the first day of standard time:
>>> dt += timedelta(days=1)
>>> dt.ctime()
'Sun Oct 27 12:00:00 2002'
The UTC offset is 1 hour:
>>> dt.utcoffset().seconds
3600
Even easier (but taking a different path through the code), the last
Wednesday before DST ends:
>>> dt = datetimetz(2002, 10, 23, 12, 0, 0, tzinfo=Amsterdam)
>>> dt.ctime()
'Wed Oct 23 12:00:00 2002'
>>> dt.utcoffset().seconds
7200
And a week later:
>>> dt += timedelta(days=7)
>>> dt.ctime()
'Wed Oct 30 12:00:00 2002'
>>> dt.utcoffset().seconds
3600
Now let's get real close to the end of DST -- in fact, one second
before it ends:
>>> dt = datetimetz(2002, 10, 27, 1, 59, 59, tzinfo=Amsterdam)
>>> dt.ctime() + ' ' + dt.tzname()
'Sun Oct 27 01:59:59 2002 MDT'
>>> dt.astimezone(UTC).ctime() + ' UTC'
'Sat Oct 26 23:59:59 2002 UTC'
Hey, that was actually an hour before it ended! That's because the
last hour of DST is unrepresentable -- at 3am, the clock jumps back to
2am; but times between 2am and 3am are (arbitrarily) assumed to be
standard time. Let's see what time it is in London at the same moment:
>>> dt1 = dt.astimezone(London)
>>> dt1.ctime() + ' ' + dt1.tzname()
'Sun Oct 27 00:59:59 2002 WDT'
Yes, in London it's also still DST, but the clock shows an hour
earlier (they are always an hour behind Amsterdam).
Now add one second, getting to 2am.
>>> dt += timedelta(seconds=1)
This lands us in standard time:
>>> dt.ctime() + ' ' + dt.tzname()
'Sun Oct 27 02:00:00 2002 MET'
Now it's 1am in UTC:
>>> dt.astimezone(UTC).ctime() + ' UTC'
'Sun Oct 27 01:00:00 2002 UTC'
And also 1am in London:
>>> dt1 = dt.astimezone(London)
>>> dt1.ctime() + ' ' + dt1.tzname()
'Sun Oct 27 01:00:00 2002 WET'
Paradox: did we lose an hour or gain an hour? That depends on your
point of view. (See also the discussion of the lost days on the
calendar in Thomas Pynchon's Mason & Dixon.)
"""
__test__ = {'demo': demo}
def _test():
import doctest, EU
return doctest.testmod(EU)
if __name__ == "__main__":
_test()