]> granicus.if.org Git - python/commitdiff
astimezone() internals: if utcoffset() returns a duration, complain if
authorTim Peters <tim.peters@gmail.com>
Thu, 2 Jan 2003 19:35:54 +0000 (19:35 +0000)
committerTim Peters <tim.peters@gmail.com>
Thu, 2 Jan 2003 19:35:54 +0000 (19:35 +0000)
dst() returns None (instead of treating that as 0).

Doc/lib/libdatetime.tex
Lib/test/test_datetime.py
Misc/NEWS
Modules/datetimemodule.c

index 72f4ed95c20e08c6d4fdd1392dd1a3332c7fea6c..60fa678a647842de3281e1b8c94b5910b3ac13fc 100644 (file)
@@ -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'
index 4fe2ad2344b06fd5a6e8352aedabd120eb0aea9a..29f81f19c3f677d256f1c632d633e7d0c66c2c10 100644 (file)
@@ -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,
index 0034710484a6f0ec5ab53737e319319503a286ea..e786af509d05e3206e3cb2b7e62090be6d2a8e44 100644 (file)
--- 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
 -------
 
index 3719a774e188f7472702b7e7981e2e0ae6c9326f..96c3e6df4f560ece48245e80eec151a7c61b1440 100644 (file)
@@ -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;