From 710fb1548ab43bcddc105c41b139b6328962de01 Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Thu, 2 Jan 2003 19:35:54 +0000 Subject: astimezone() internals: if utcoffset() returns a duration, complain if dst() returns None (instead of treating that as 0). --- Doc/lib/libdatetime.tex | 32 +++++++++++++++++++------------- Lib/test/test_datetime.py | 17 +++++++++++++++++ Misc/NEWS | 4 ++++ Modules/datetimemodule.c | 6 +++++- 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 . + 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; -- cgit v0.12