summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2003-01-02 19:35:54 (GMT)
committerTim Peters <tim.peters@gmail.com>2003-01-02 19:35:54 (GMT)
commit710fb1548ab43bcddc105c41b139b6328962de01 (patch)
tree7047ed7c552cb5cc43517e5b06dfbc7dee038a36
parent0123139d665c02fa731511d32a31724137c8eca0 (diff)
downloadcpython-710fb1548ab43bcddc105c41b139b6328962de01.zip
cpython-710fb1548ab43bcddc105c41b139b6328962de01.tar.gz
cpython-710fb1548ab43bcddc105c41b139b6328962de01.tar.bz2
astimezone() internals: if utcoffset() returns a duration, complain if
dst() returns None (instead of treating that as 0).
-rw-r--r--Doc/lib/libdatetime.tex32
-rw-r--r--Lib/test/test_datetime.py17
-rw-r--r--Misc/NEWS4
-rw-r--r--Modules/datetimemodule.c6
4 files changed, 45 insertions, 14 deletions
diff --git a/Doc/lib/libdatetime.tex b/Doc/lib/libdatetime.tex
index 72f4ed9..60fa678 100644
--- a/Doc/lib/libdatetime.tex
+++ b/Doc/lib/libdatetime.tex
@@ -893,21 +893,14 @@ implement all of them.
return CONSTANT # fixed-offset class
return CONSTANT + self.dst(dt) # daylight-aware class
\end{verbatim}
-\end{methoddesc}
-\begin{methoddesc}{tzname}{self, dt}
- Return the timezone name corresponding to the \class{datetime} represented
- by \var{dt}, as a string. Nothing about string names is defined by the
- \module{datetime} module, and there's no requirement that it mean anything
- in particular. For example, "GMT", "UTC", "-500", "-5:00", "EDT",
- "US/Eastern", "America/New York" are all valid replies. Return
- \code{None} if a string name isn't known. Note that this is a method
- rather than a fixed string primarily because some \class{tzinfo} objects
- will wish to return different names depending on the specific value
- of \var{dt} passed, especially if the \class{tzinfo} class is
- accounting for daylight time.
+ If \method{utcoffset()} does not return \code{None},
+ \method{dst()} should not return \code{None} either.
+
+
\end{methoddesc}
+
\begin{methoddesc}{dst}{self, dt}
Return the daylight savings time (DST) adjustment, in minutes east of
UTC, or \code{None} if DST information isn't known. Return \code{0} if
@@ -937,6 +930,19 @@ implement all of them.
but cannot detect violations; it's the programmer's responsibility to
ensure it.
+\begin{methoddesc}{tzname}{self, dt}
+ Return the timezone name corresponding to the \class{datetime} represented
+ by \var{dt}, as a string. Nothing about string names is defined by the
+ \module{datetime} module, and there's no requirement that it mean anything
+ in particular. For example, "GMT", "UTC", "-500", "-5:00", "EDT",
+ "US/Eastern", "America/New York" are all valid replies. Return
+ \code{None} if a string name isn't known. Note that this is a method
+ rather than a fixed string primarily because some \class{tzinfo} objects
+ will wish to return different names depending on the specific value
+ of \var{dt} passed, especially if the \class{tzinfo} class is
+ accounting for daylight time.
+\end{methoddesc}
+
\end{methoddesc}
These methods are called by a \class{datetimetz} or \class{timetz} object,
@@ -1379,7 +1385,7 @@ Instance methods:
\begin{verbatim}
>>> from datetime import *
>>> class TZ(tzinfo):
-... def utcoffset(self, dt): return -399
+... def utcoffset(self, dt): return timedelta(minutes=-399)
...
>>> datetimetz(2002, 12, 25, tzinfo=TZ()).isoformat(' ')
'2002-12-25 00:00:00-06:39'
diff --git a/Lib/test/test_datetime.py b/Lib/test/test_datetime.py
index 4fe2ad2..29f81f1 100644
--- a/Lib/test/test_datetime.py
+++ b/Lib/test/test_datetime.py
@@ -2591,6 +2591,8 @@ class TestTimezoneConversions(unittest.TestCase):
dston = datetimetz(2002, 4, 7, 2)
dstoff = datetimetz(2002, 10, 27, 2)
+ theclass = datetimetz
+
# Check a time that's inside DST.
def checkinside(self, dt, tz, utc, dston, dstoff):
self.assertEqual(dt.dst(), HOUR)
@@ -2729,6 +2731,21 @@ class TestTimezoneConversions(unittest.TestCase):
got = sixutc.astimezone(Eastern).astimezone(None)
self.assertEqual(expected, got)
+ def test_bogus_dst(self):
+ class ok(tzinfo):
+ def utcoffset(self, dt): return HOUR
+ def dst(self, dt): return HOUR
+
+ now = self.theclass.now().replace(tzinfo=utc_real)
+ # Doesn't blow up.
+ now.astimezone(ok())
+
+ # Does blow up.
+ class notok(ok):
+ def dst(self, dt): return None
+ self.assertRaises(ValueError, now.astimezone, notok())
+
+
def test_suite():
allsuites = [unittest.makeSuite(klass, 'test')
for klass in (TestModule,
diff --git a/Misc/NEWS b/Misc/NEWS
index 0034710..e786af5 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -22,6 +22,10 @@ Extension modules
today() and now() now round system timestamps to the closest
microsecond <http://www.python.org/sf/661086>.
+ In dt.asdatetime(tz), if tz.utcoffset(dt) returns a duration,
+ ValueError is raised of tz.dst(dt) returns None (2.3a1 treated it
+ as 0 instead).
+
Library
-------
diff --git a/Modules/datetimemodule.c b/Modules/datetimemodule.c
index 3719a77..96c3e6d 100644
--- a/Modules/datetimemodule.c
+++ b/Modules/datetimemodule.c
@@ -4805,7 +4805,11 @@ datetimetz_astimezone(PyDateTime_DateTimeTZ *self, PyObject *args,
resdst = call_dst(tzinfo, result, &none);
if (resdst == -1 && PyErr_Occurred())
goto Fail;
- /* None and 0 dst() results are the same to us here. Debatable. */
+ if (none) {
+ PyErr_SetString(PyExc_ValueError, "astimezone(): utcoffset() "
+ "returned a duration but dst() returned None");
+ goto Fail;
+ }
total_added_to_result = resoff - resdst - selfoff;
if (total_added_to_result != 0) {
mm += total_added_to_result;