Skip to content

Commit 12c1787

Browse files
bpo-30699: Improve example on datetime tzinfo instances (GH-4290)
* Improve example on tzinfo instances Move from GMTX to TZX when naming the classes, as GMT1 might be rather confusing as seen in the reported issue. In addition, move to UTC over GMT and improve the tzname implementation. * Simplify datetime with tzinfo example Move the example in the documentation to just use timezone.utc and a user defined Kabul timezone rather than having two user defined timezones with DST. Kabul timezone is still interesting as it changes its offset but not based on DST. This is more accurate as the previous example was missing information about the fold attribute. Additionally, implementing the fold attribute was rather complex and probably not relevant enough for the section "datetime with tzinfo". (cherry picked from commit f0b5ae4) Co-authored-by: Mario Corchero <mcorcherojim@bloomberg.net>
1 parent cad4ff6 commit 12c1787

File tree

1 file changed

+60
-51
lines changed

1 file changed

+60
-51
lines changed

Doc/library/datetime.rst

Lines changed: 60 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,56 +1348,64 @@ Examples of working with datetime objects:
13481348

13491349
Using datetime with tzinfo:
13501350

1351-
>>> from datetime import timedelta, datetime, tzinfo
1352-
>>> class GMT1(tzinfo):
1351+
>>> from datetime import timedelta, datetime, tzinfo, timezone
1352+
>>> class KabulTz(tzinfo):
1353+
... # Kabul used +4 until 1945, when they moved to +4:30
1354+
... UTC_MOVE_DATE = datetime(1944, 12, 31, 20, tzinfo=timezone.utc)
13531355
... def utcoffset(self, dt):
1354-
... return timedelta(hours=1) + self.dst(dt)
1355-
... def dst(self, dt):
1356-
... # DST starts last Sunday in March
1357-
... d = datetime(dt.year, 4, 1) # ends last Sunday in October
1358-
... self.dston = d - timedelta(days=d.weekday() + 1)
1359-
... d = datetime(dt.year, 11, 1)
1360-
... self.dstoff = d - timedelta(days=d.weekday() + 1)
1361-
... if self.dston <= dt.replace(tzinfo=None) < self.dstoff:
1362-
... return timedelta(hours=1)
1356+
... if dt.year < 1945:
1357+
... return timedelta(hours=4)
1358+
... elif (1945, 1, 1, 0, 0) <= dt.timetuple()[:5] < (1945, 1, 1, 0, 30):
1359+
... # If dt falls in the imaginary range, use fold to decide how
1360+
... # to resolve. See PEP495
1361+
... return timedelta(hours=4, minutes=(30 if dt.fold else 0))
13631362
... else:
1364-
... return timedelta(0)
1365-
... def tzname(self,dt):
1366-
... return "GMT +1"
1363+
... return timedelta(hours=4, minutes=30)
1364+
...
1365+
... def fromutc(self, dt):
1366+
... # A custom implementation is required for fromutc as
1367+
... # the input to this function is a datetime with utc values
1368+
... # but with a tzinfo set to self
1369+
... # See datetime.astimezone or fromtimestamp
1370+
...
1371+
... # Follow same validations as in datetime.tzinfo
1372+
... if not isinstance(dt, datetime):
1373+
... raise TypeError("fromutc() requires a datetime argument")
1374+
... if dt.tzinfo is not self:
1375+
... raise ValueError("dt.tzinfo is not self")
1376+
...
1377+
... if dt.replace(tzinfo=timezone.utc) >= self.UTC_MOVE_DATE:
1378+
... return dt + timedelta(hours=4, minutes=30)
1379+
... else:
1380+
... return dt + timedelta(hours=4)
13671381
...
1368-
>>> class GMT2(tzinfo):
1369-
... def utcoffset(self, dt):
1370-
... return timedelta(hours=2) + self.dst(dt)
13711382
... def dst(self, dt):
1372-
... d = datetime(dt.year, 4, 1)
1373-
... self.dston = d - timedelta(days=d.weekday() + 1)
1374-
... d = datetime(dt.year, 11, 1)
1375-
... self.dstoff = d - timedelta(days=d.weekday() + 1)
1376-
... if self.dston <= dt.replace(tzinfo=None) < self.dstoff:
1377-
... return timedelta(hours=1)
1383+
... return timedelta(0)
1384+
...
1385+
... def tzname(self, dt):
1386+
... if dt >= self.UTC_MOVE_DATE:
1387+
... return "+04:30"
13781388
... else:
1379-
... return timedelta(0)
1380-
... def tzname(self,dt):
1381-
... return "GMT +2"
1389+
... return "+04"
13821390
...
1383-
>>> gmt1 = GMT1()
1384-
>>> # Daylight Saving Time
1385-
>>> dt1 = datetime(2006, 11, 21, 16, 30, tzinfo=gmt1)
1386-
>>> dt1.dst()
1387-
datetime.timedelta(0)
1388-
>>> dt1.utcoffset()
1389-
datetime.timedelta(seconds=3600)
1390-
>>> dt2 = datetime(2006, 6, 14, 13, 0, tzinfo=gmt1)
1391-
>>> dt2.dst()
1392-
datetime.timedelta(seconds=3600)
1393-
>>> dt2.utcoffset()
1394-
datetime.timedelta(seconds=7200)
1391+
... def __repr__(self):
1392+
... return f"{self.__class__.__name__}()"
1393+
...
1394+
>>> tz1 = KabulTz()
1395+
>>> # Datetime before the change
1396+
>>> dt1 = datetime(1900, 11, 21, 16, 30, tzinfo=tz1)
1397+
>>> print(dt1.utcoffset())
1398+
4:00:00
1399+
>>> # Datetime after the change
1400+
>>> dt2 = datetime(2006, 6, 14, 13, 0, tzinfo=tz1)
1401+
>>> print(dt2.utcoffset())
1402+
4:30:00
13951403
>>> # Convert datetime to another time zone
1396-
>>> dt3 = dt2.astimezone(GMT2())
1397-
>>> dt3 # doctest: +ELLIPSIS
1398-
datetime.datetime(2006, 6, 14, 14, 0, tzinfo=<GMT2 object at 0x...>)
1399-
>>> dt2 # doctest: +ELLIPSIS
1400-
datetime.datetime(2006, 6, 14, 13, 0, tzinfo=<GMT1 object at 0x...>)
1404+
>>> dt3 = dt2.astimezone(timezone.utc)
1405+
>>> dt3
1406+
datetime.datetime(2006, 6, 14, 8, 30, tzinfo=datetime.timezone.utc)
1407+
>>> dt2
1408+
datetime.datetime(2006, 6, 14, 13, 0, tzinfo=KabulTz())
14011409
>>> dt2.utctimetuple() == dt3.utctimetuple()
14021410
True
14031411

@@ -1639,26 +1647,27 @@ Instance methods:
16391647
Example:
16401648

16411649
>>> from datetime import time, tzinfo, timedelta
1642-
>>> class GMT1(tzinfo):
1650+
>>> class TZ1(tzinfo):
16431651
... def utcoffset(self, dt):
16441652
... return timedelta(hours=1)
16451653
... def dst(self, dt):
16461654
... return timedelta(0)
16471655
... def tzname(self,dt):
1648-
... return "Europe/Prague"
1656+
... return "+01:00"
1657+
... def __repr__(self):
1658+
... return f"{self.__class__.__name__}()"
16491659
...
1650-
>>> t = time(12, 10, 30, tzinfo=GMT1())
1651-
>>> t # doctest: +ELLIPSIS
1652-
datetime.time(12, 10, 30, tzinfo=<GMT1 object at 0x...>)
1653-
>>> gmt = GMT1()
1660+
>>> t = time(12, 10, 30, tzinfo=TZ1())
1661+
>>> t
1662+
datetime.time(12, 10, 30, tzinfo=TZ1())
16541663
>>> t.isoformat()
16551664
'12:10:30+01:00'
16561665
>>> t.dst()
16571666
datetime.timedelta(0)
16581667
>>> t.tzname()
1659-
'Europe/Prague'
1668+
'+01:00'
16601669
>>> t.strftime("%H:%M:%S %Z")
1661-
'12:10:30 Europe/Prague'
1670+
'12:10:30 +01:00'
16621671
>>> 'The {} is {:%H:%M}.'.format("time", t)
16631672
'The time is 12:10.'
16641673

0 commit comments

Comments
 (0)