[Python-checkins] r62107 - sandbox/trunk/datetime/US.py
david.goodger
python-checkins at python.org
Wed Apr 2 22:14:56 CEST 2008
Author: david.goodger
Date: Wed Apr 2 22:14:56 2008
New Revision: 62107
Modified:
sandbox/trunk/datetime/US.py
Log:
implement the new DST rules (2007 forward)
Modified: sandbox/trunk/datetime/US.py
==============================================================================
--- sandbox/trunk/datetime/US.py (original)
+++ sandbox/trunk/datetime/US.py Wed Apr 2 22:14:56 2008
@@ -2,15 +2,55 @@
from datetime import tzinfo
from datetime import timedelta
-from dateutil import SUNDAY, APRIL, OCTOBER, weekday_of_month
+from dateutil import SUNDAY, MARCH, APRIL, OCTOBER, NOVEMBER, weekday_of_month
__all__ = ['USTimeZone', 'Eastern', 'Central', 'Mountain', 'Pacific']
+
+class DST_Rules(object):
+
+ """Encapsulate the rules for a DST change date."""
+
+ # Assumes that DST changes happen on Sunday mornings.
+
+ def __init__(self, month, sunday_index):
+ """
+ Parameters:
+
+ * `month`: Month of DST change (1=January, 12=December).
+ * `sunday_index`: Base-0 index of Sunday (0=first, 1=second, -1=last).
+ """
+ self.month = month
+ self.sunday_index = sunday_index
+ self.dummy_date = datetime(year=1, month=month, day=1, hour=self.hour)
+
+ def date(self, year):
+ """Return the date of the change in the given `year`."""
+ date = weekday_of_month(
+ SUNDAY, self.dummy_date.replace(year=year), self.sunday_index)
+ assert date.month == self.dummy_date.month
+ return date
+
+
+class DST_Start(DST_Rules):
+
+ # DST starts at 2am (standard time):
+ hour = 2
+
+
+class DST_End(DST_Rules):
+
+ # DST ends at 1am (standard time; 2am DST time):
+ hour = 1
+
+
class USTimeZone(tzinfo):
- "A class capturing the current (2002) rules for United States time zones."
- # XXX Note that in 2007 the rules are changing:
- # XXX 2nd Sunday in March, 1st Sunday in November.
- # XXX Anybody want to volunteer a fix for this code?
+ """
+ A class capturing the pre- and post-2007 daylight saving time (DST)
+ rules for United States time zones.
+ """
+ # Note that in 2007 the rules changed. The comment below refers to
+ # the old rules. See USTimeZone.dst_rules for specific dates.
# A seemingly intractable problem: when DST ends, there's a one-hour
# slice that repeats in "naive time". That is, when the naive clock
@@ -49,10 +89,18 @@
dstoff = timedelta(hours=1)
zero = timedelta(0)
- # DST starts at 2am (standard time) on the first Sunday in April.
- start = datetime(1, APRIL, 1, 2)
- # and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct.
- end = datetime(1, OCTOBER, 1, 1)
+
+ # [(first year, start rule, end rule), ...]
+ dst_rules = [
+ (2007,
+ DST_Start(month=MARCH, sunday_index=1),
+ DST_End(month=NOVEMBER, sunday_index=0)),
+ (1987,
+ DST_Start(month=APRIL, sunday_index=0),
+ DST_End(month=OCTOBER, sunday_index=-1)),
+ ]
+ # Ensure that the rules are in reverse chronological order:
+ dst_rules.sort(reverse=True)
def __init__(self, stdhours, stdname, dstname):
self.stdoff = timedelta(hours=stdhours)
@@ -76,13 +124,27 @@
assert dt.tzinfo is self
- # Find first Sunday in April.
- start = weekday_of_month(SUNDAY, self.start.replace(year=dt.year), 0)
- assert start.weekday() == 6 and start.month == 4 and start.day <= 7
-
- # Find last Sunday in October.
- end = weekday_of_month(SUNDAY, self.end.replace(year=dt.year), -1)
- assert end.weekday() == 6 and end.month == 10 and end.day >= 25
+ for (first_year, dst_start, dst_end) in self.dst_rules:
+ if dt.year >= first_year:
+ break
+ else:
+ # As above, an exception instead may be sensible here.
+ return self.zero
+
+ start = dst_start.date(dt.year)
+ assert start.weekday() == 6
+ if dt.year >= 2007:
+ #import pdb ; pdb.set_trace()
+ assert 8 <= start.day <= 14
+ else:
+ assert start.day <= 7
+
+ end = dst_end.date(dt.year)
+ assert end.weekday() == 6
+ if dt.year >= 2007:
+ assert end.day <= 7
+ else:
+ assert end.day >= 25
# Can't compare naive to aware objects, so strip the timezone from
# dt first.
@@ -91,6 +153,7 @@
else:
return self.zero
+
Eastern = USTimeZone(-5, "EST", "EDT")
Central = USTimeZone(-6, "CST", "CDT")
Mountain = USTimeZone(-7, "MST", "MDT")
@@ -233,6 +296,24 @@
EST
(2002, 10, 27, 1, 0, 0, 6, 300, 0)
Sun Oct 27 01:00:00 2002
+
+Post-2007 rules:
+
+Right before DST starts.
+>>> before = datetime(2007, 3, 11, 1, 59, 59, tzinfo=Eastern)
+>>> printstuff(before)
+2007-03-11 01:59:59-05:00
+EST
+(2007, 3, 11, 1, 59, 59, 6, 70, 0)
+Sun Mar 11 01:59:59 2007
+
+Right when DST starts.
+>>> after = before + timedelta(seconds=1)
+>>> printstuff(after)
+2007-03-11 02:00:00-04:00
+EDT
+(2007, 3, 11, 2, 0, 0, 6, 70, 1)
+Sun Mar 11 02:00:00 2007
"""
__test__ = {'brainbuster': brainbuster_test}
More information about the Python-checkins
mailing list