Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 397301e

Browse files
committed
The tzinfo methods utcoffset() and dst() must return a timedelta object
(or None) now. In 2.3a1 they could also return an int or long, but that was an unhelpfully redundant leftover from an earlier version wherein they couldn't return a timedelta. TOOWTDI.
1 parent 4abd5f0 commit 397301e

5 files changed

Lines changed: 84 additions & 77 deletions

File tree

Doc/lib/libdatetime.tex

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -231,18 +231,19 @@ \subsection{\class{timedelta} Objects \label{datetime-timedelta}}
231231
{(1)}
232232
\lineiii{\var{t1} = \var{t2} // \var{i}}
233233
{The floor is computed and the remainder (if any) is thrown away.}
234-
{(2)}
234+
{(3)}
235235
\lineiii{+\var{t1}}
236236
{Returns a \class{timedelta} object with the same value.}
237-
{}
237+
{(2)}
238238
\lineiii{-\var{t1}}
239239
{equivalent to \class{timedelta}(-\var{t1.days}, -\var{t1.seconds},
240240
-\var{t1.microseconds}),and to \var{t1}* -1.}
241-
{(1)(3)}
241+
{(1)(4)}
242242
\lineiii{abs(\var{t})}
243243
{equivalent to +\var{t} when \code{t.days >= 0}, and to
244-
-\var{t} when \code{t.days < 0}.}
245-
{(1)}
244+
-\var{t} when \code{t.days < 0}.
245+
overflow.}
246+
{(2)}
246247
\end{tableiii}
247248
\noindent
248249
Notes:
@@ -252,9 +253,12 @@ \subsection{\class{timedelta} Objects \label{datetime-timedelta}}
252253
This is exact, but may overflow.
253254

254255
\item[(2)]
255-
Division by 0 raises \exception{ZeroDivisionError}.
256+
This is exact, and cannot overflow.
256257

257258
\item[(3)]
259+
Division by 0 raises \exception{ZeroDivisionError}.
260+
261+
\item[(4)]
258262
-\var{timedelta.max} is not representable as a \class{timedelta} object.
259263
\end{description}
260264

@@ -883,11 +887,10 @@ \subsection{\class{tzinfo} Objects \label{datetime-tzinfo}}
883887
\class{tzinfo} object represents both time zone and DST adjustments,
884888
\method{utcoffset()} should return their sum. If the UTC offset
885889
isn't known, return \code{None}. Else the value returned must be
886-
an integer, in the range -1439 to 1439 inclusive (1440 = 24*60;
887-
the magnitude of the offset must be less than one day), or a
888-
\class{timedelta} object representing a whole number of minutes
889-
in the same range. Most implementations of \method{utcoffset()}
890-
will probably look like one of these two:
890+
a \class{timedelta} object specifying a whole number of minutes in the
891+
range -1439 to 1439 inclusive (1440 = 24*60; the magnitude of the offset
892+
must be less than one day). Most implementations of
893+
\method{utcoffset()} will probably look like one of these two:
891894

892895
\begin{verbatim}
893896
return CONSTANT # fixed-offset class
@@ -896,16 +899,14 @@ \subsection{\class{tzinfo} Objects \label{datetime-tzinfo}}
896899

897900
If \method{utcoffset()} does not return \code{None},
898901
\method{dst()} should not return \code{None} either.
899-
900-
901902
\end{methoddesc}
902903

903904

904905
\begin{methoddesc}{dst}{self, dt}
905906
Return the daylight savings time (DST) adjustment, in minutes east of
906907
UTC, or \code{None} if DST information isn't known. Return \code{0} if
907908
DST is not in effect.
908-
If DST is in effect, return the offset as an integer or
909+
If DST is in effect, return the offset as a
909910
\class{timedelta} object (see \method{utcoffset()} for details).
910911
Note that DST offset, if applicable, has
911912
already been added to the UTC offset returned by

Doc/lib/tzinfo-examples.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
from datetime import tzinfo
1+
from datetime import tzinfo, timedelta
2+
3+
ZERO = timedelta(0)
24

35
class UTC(tzinfo):
46
"""UTC"""
57

68
def utcoffset(self, dt):
7-
return 0
9+
return ZERO
810

911
def tzname(self, dt):
1012
return "UTC"
1113

1214
def dst(self, dt):
13-
return 0
15+
return ZERO
1416

1517
class FixedOffset(tzinfo):
1618
"""Fixed offset in minutes east from UTC."""
@@ -26,8 +28,7 @@ def tzname(self, dt):
2628
return self.__name
2729

2830
def dst(self, dt):
29-
# It depends on more than we know in an example.
30-
return None # Indicate we don't know
31+
return ZERO
3132

3233
import time
3334

@@ -43,9 +44,9 @@ def _isdst(self, dt):
4344

4445
def utcoffset(self, dt):
4546
if self._isdst(dt):
46-
return -time.timezone/60
47+
return timedelta(seconds=-time.timezone)
4748
else:
48-
return -time.altzone/60
49+
return timedelta(seconds=-time.altzone)
4950

5051
def tzname(self, dt):
5152
return time.tzname[self._isdst(dt)]

Lib/test/test_datetime.py

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ def test_constants(self):
2626

2727
class FixedOffset(tzinfo):
2828
def __init__(self, offset, name, dstoffset=42):
29+
if isinstance(offset, int):
30+
offset = timedelta(minutes=offset)
31+
if isinstance(dstoffset, int):
32+
dstoffset = timedelta(minutes=dstoffset)
2933
self.__offset = offset
3034
self.__name = name
3135
self.__dstoffset = dstoffset
@@ -72,9 +76,9 @@ def test_normal(self):
7276
fo = FixedOffset(3, "Three")
7377
self.failUnless(isinstance(fo, tzinfo))
7478
for dt in datetime.now(), None:
75-
self.assertEqual(fo.utcoffset(dt), 3)
79+
self.assertEqual(fo.utcoffset(dt), timedelta(minutes=3))
7680
self.assertEqual(fo.tzname(dt), "Three")
77-
self.assertEqual(fo.dst(dt), 42)
81+
self.assertEqual(fo.dst(dt), timedelta(minutes=42))
7882

7983
def test_pickling_base(self):
8084
import pickle, cPickle
@@ -94,18 +98,19 @@ def test_pickling_subclass(self):
9498
import pickle, cPickle
9599

96100
# Make sure we can pickle/unpickle an instance of a subclass.
97-
orig = PicklableFixedOffset(-300, 'cookie')
101+
offset = timedelta(minutes=-300)
102+
orig = PicklableFixedOffset(offset, 'cookie')
98103
self.failUnless(isinstance(orig, tzinfo))
99104
self.failUnless(type(orig) is PicklableFixedOffset)
100-
self.assertEqual(orig.utcoffset(None), -300)
105+
self.assertEqual(orig.utcoffset(None), offset)
101106
self.assertEqual(orig.tzname(None), 'cookie')
102107
for pickler in pickle, cPickle:
103108
for binary in 0, 1:
104109
green = pickler.dumps(orig, binary)
105110
derived = pickler.loads(green)
106111
self.failUnless(isinstance(derived, tzinfo))
107112
self.failUnless(type(derived) is PicklableFixedOffset)
108-
self.assertEqual(derived.utcoffset(None), -300)
113+
self.assertEqual(derived.utcoffset(None), offset)
109114
self.assertEqual(derived.tzname(None), 'cookie')
110115

111116
#############################################################################
@@ -1562,7 +1567,8 @@ def test_argument_passing(self):
15621567
# A datetimetz passes itself on, a timetz passes None.
15631568
class introspective(tzinfo):
15641569
def tzname(self, dt): return dt and "real" or "none"
1565-
def utcoffset(self, dt): return dt and 42 or -42
1570+
def utcoffset(self, dt):
1571+
return timedelta(minutes = dt and 42 or -42)
15661572
dst = utcoffset
15671573

15681574
obj = cls(1, 2, 3, tzinfo=introspective())
@@ -1593,7 +1599,7 @@ def utcoffset(self, dt): pass
15931599
def test_utc_offset_out_of_bounds(self):
15941600
class Edgy(tzinfo):
15951601
def __init__(self, offset):
1596-
self.offset = offset
1602+
self.offset = timedelta(minutes=offset)
15971603
def utcoffset(self, dt):
15981604
return self.offset
15991605

@@ -1629,39 +1635,32 @@ def tzname(self, dt): return None
16291635
self.failUnless(t.dst() is None)
16301636
self.failUnless(t.tzname() is None)
16311637

1632-
class C2(tzinfo):
1633-
def utcoffset(self, dt): return -1439
1634-
def dst(self, dt): return 1439
1635-
def tzname(self, dt): return "aname"
16361638
class C3(tzinfo):
16371639
def utcoffset(self, dt): return timedelta(minutes=-1439)
16381640
def dst(self, dt): return timedelta(minutes=1439)
16391641
def tzname(self, dt): return "aname"
1640-
for t in cls(1, 1, 1, tzinfo=C2()), cls(1, 1, 1, tzinfo=C3()):
1641-
self.assertEqual(t.utcoffset(), timedelta(minutes=-1439))
1642-
self.assertEqual(t.dst(), timedelta(minutes=1439))
1643-
self.assertEqual(t.tzname(), "aname")
1642+
t = cls(1, 1, 1, tzinfo=C3())
1643+
self.assertEqual(t.utcoffset(), timedelta(minutes=-1439))
1644+
self.assertEqual(t.dst(), timedelta(minutes=1439))
1645+
self.assertEqual(t.tzname(), "aname")
16441646

16451647
# Wrong types.
16461648
class C4(tzinfo):
16471649
def utcoffset(self, dt): return "aname"
1648-
def dst(self, dt): return ()
1650+
def dst(self, dt): return 7
16491651
def tzname(self, dt): return 0
16501652
t = cls(1, 1, 1, tzinfo=C4())
16511653
self.assertRaises(TypeError, t.utcoffset)
16521654
self.assertRaises(TypeError, t.dst)
16531655
self.assertRaises(TypeError, t.tzname)
16541656

16551657
# Offset out of range.
1656-
class C5(tzinfo):
1657-
def utcoffset(self, dt): return -1440
1658-
def dst(self, dt): return 1440
16591658
class C6(tzinfo):
16601659
def utcoffset(self, dt): return timedelta(hours=-24)
16611660
def dst(self, dt): return timedelta(hours=24)
1662-
for t in cls(1, 1, 1, tzinfo=C5()), cls(1, 1, 1, tzinfo=C6()):
1663-
self.assertRaises(ValueError, t.utcoffset)
1664-
self.assertRaises(ValueError, t.dst)
1661+
t = cls(1, 1, 1, tzinfo=C6())
1662+
self.assertRaises(ValueError, t.utcoffset)
1663+
self.assertRaises(ValueError, t.dst)
16651664

16661665
# Not a whole number of minutes.
16671666
class C7(tzinfo):
@@ -1679,9 +1678,11 @@ def test_aware_compare(self):
16791678
class OperandDependentOffset(tzinfo):
16801679
def utcoffset(self, t):
16811680
if t.minute < 10:
1682-
return t.minute # d0 and d1 equal after adjustment
1681+
# d0 and d1 equal after adjustment
1682+
return timedelta(minutes=t.minute)
16831683
else:
1684-
return 59 # d2 off in the weeds
1684+
# d2 off in the weeds
1685+
return timedelta(minutes=59)
16851686

16861687
base = cls(8, 9, 10, tzinfo=OperandDependentOffset())
16871688
d0 = base.replace(minute=3)
@@ -1937,9 +1938,9 @@ def test_mixed_compare(self):
19371938
# In timetz w/ identical tzinfo objects, utcoffset is ignored.
19381939
class Varies(tzinfo):
19391940
def __init__(self):
1940-
self.offset = 22
1941+
self.offset = timedelta(minutes=22)
19411942
def utcoffset(self, t):
1942-
self.offset += 1
1943+
self.offset += timedelta(minutes=1)
19431944
return self.offset
19441945

19451946
v = Varies()
@@ -2028,7 +2029,8 @@ def utcoffset(self, dt): return None
20282029

20292030
# Try a bogus uctoffset.
20302031
class Bogus(tzinfo):
2031-
def utcoffset(self, dt): return 1440 # out of bounds
2032+
def utcoffset(self, dt):
2033+
return timedelta(minutes=1440) # out of bounds
20322034
t1 = self.theclass(2, 2, 2, tzinfo=Bogus())
20332035
t2 = self.theclass(2, 2, 2, tzinfo=FixedOffset(0, ""))
20342036
self.assertRaises(ValueError, lambda: t1 == t2)
@@ -2259,6 +2261,8 @@ def test_tzinfo_timetuple(self):
22592261
# DST flag.
22602262
class DST(tzinfo):
22612263
def __init__(self, dstvalue):
2264+
if isinstance(dstvalue, int):
2265+
dstvalue = timedelta(minutes=dstvalue)
22622266
self.dstvalue = dstvalue
22632267
def dst(self, dt):
22642268
return self.dstvalue
@@ -2291,6 +2295,8 @@ def dst(self, dt):
22912295
def test_utctimetuple(self):
22922296
class DST(tzinfo):
22932297
def __init__(self, dstvalue):
2298+
if isinstance(dstvalue, int):
2299+
dstvalue = timedelta(minutes=dstvalue)
22942300
self.dstvalue = dstvalue
22952301
def dst(self, dt):
22962302
return self.dstvalue
@@ -2303,7 +2309,7 @@ def dst(self, dt):
23032309
class UOFS(DST):
23042310
def __init__(self, uofs, dofs=None):
23052311
DST.__init__(self, dofs)
2306-
self.uofs = uofs
2312+
self.uofs = timedelta(minutes=uofs)
23072313
def utcoffset(self, dt):
23082314
return self.uofs
23092315

@@ -2454,9 +2460,11 @@ def test_aware_subtract(self):
24542460
class OperandDependentOffset(tzinfo):
24552461
def utcoffset(self, t):
24562462
if t.minute < 10:
2457-
return t.minute # d0 and d1 equal after adjustment
2463+
# d0 and d1 equal after adjustment
2464+
return timedelta(minutes=t.minute)
24582465
else:
2459-
return 59 # d2 off in the weeds
2466+
# d2 off in the weeds
2467+
return timedelta(minutes=59)
24602468

24612469
base = cls(8, 9, 10, 11, 12, 13, 14, tzinfo=OperandDependentOffset())
24622470
d0 = base.replace(minute=3)
@@ -2502,9 +2510,9 @@ def test_mixed_compare(self):
25022510
# In datetimetz w/ identical tzinfo objects, utcoffset is ignored.
25032511
class Varies(tzinfo):
25042512
def __init__(self):
2505-
self.offset = 22
2513+
self.offset = timedelta(minutes=22)
25062514
def utcoffset(self, t):
2507-
self.offset += 1
2515+
self.offset += timedelta(minutes=1)
25082516
return self.offset
25092517

25102518
v = Varies()

Misc/NEWS

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@ Extension modules
2727
microsecond <http://www.python.org/sf/661086>.
2828

2929
In dt.asdatetime(tz), if tz.utcoffset(dt) returns a duration,
30-
ValueError is raised of tz.dst(dt) returns None (2.3a1 treated it
30+
ValueError is raised if tz.dst(dt) returns None (2.3a1 treated it
3131
as 0 instead).
32-
32+
33+
The tzinfo methods utcoffset() and dst() must return a timedelta object
34+
(or None) now. In 2.3a1 they could also return an int or long, but that
35+
was an unhelpfully redundant leftover from an earlier version wherein
36+
they couldn't return a timedelta. TOOWTDI.
37+
3338
Library
3439
-------
3540

0 commit comments

Comments
 (0)