Commit f0b5ae45 authored by Mario Corchero's avatar Mario Corchero Committed by Victor Stinner

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".
parent ca612a97
...@@ -1365,56 +1365,64 @@ Examples of working with datetime objects: ...@@ -1365,56 +1365,64 @@ Examples of working with datetime objects:
Using datetime with tzinfo: Using datetime with tzinfo:
>>> from datetime import timedelta, datetime, tzinfo >>> from datetime import timedelta, datetime, tzinfo, timezone
>>> class GMT1(tzinfo): >>> class KabulTz(tzinfo):
... # Kabul used +4 until 1945, when they moved to +4:30
... UTC_MOVE_DATE = datetime(1944, 12, 31, 20, tzinfo=timezone.utc)
... def utcoffset(self, dt): ... def utcoffset(self, dt):
... return timedelta(hours=1) + self.dst(dt) ... if dt.year < 1945:
... def dst(self, dt): ... return timedelta(hours=4)
... # DST starts last Sunday in March ... elif (1945, 1, 1, 0, 0) <= dt.timetuple()[:5] < (1945, 1, 1, 0, 30):
... d = datetime(dt.year, 4, 1) # ends last Sunday in October ... # If dt falls in the imaginary range, use fold to decide how
... self.dston = d - timedelta(days=d.weekday() + 1) ... # to resolve. See PEP495
... d = datetime(dt.year, 11, 1) ... return timedelta(hours=4, minutes=(30 if dt.fold else 0))
... self.dstoff = d - timedelta(days=d.weekday() + 1)
... if self.dston <= dt.replace(tzinfo=None) < self.dstoff:
... return timedelta(hours=1)
... else: ... else:
... return timedelta(0) ... return timedelta(hours=4, minutes=30)
... def tzname(self,dt): ...
... return "GMT +1" ... def fromutc(self, dt):
... # A custom implementation is required for fromutc as
... # the input to this function is a datetime with utc values
... # but with a tzinfo set to self
... # See datetime.astimezone or fromtimestamp
...
... # Follow same validations as in datetime.tzinfo
... if not isinstance(dt, datetime):
... raise TypeError("fromutc() requires a datetime argument")
... if dt.tzinfo is not self:
... raise ValueError("dt.tzinfo is not self")
...
... if dt.replace(tzinfo=timezone.utc) >= self.UTC_MOVE_DATE:
... return dt + timedelta(hours=4, minutes=30)
... else:
... return dt + timedelta(hours=4)
... ...
>>> class GMT2(tzinfo):
... def utcoffset(self, dt):
... return timedelta(hours=2) + self.dst(dt)
... def dst(self, dt): ... def dst(self, dt):
... d = datetime(dt.year, 4, 1) ... return timedelta(0)
... self.dston = d - timedelta(days=d.weekday() + 1) ...
... d = datetime(dt.year, 11, 1) ... def tzname(self, dt):
... self.dstoff = d - timedelta(days=d.weekday() + 1) ... if dt >= self.UTC_MOVE_DATE:
... if self.dston <= dt.replace(tzinfo=None) < self.dstoff: ... return "+04:30"
... return timedelta(hours=1)
... else: ... else:
... return timedelta(0) ... return "+04"
... def tzname(self,dt):
... return "GMT +2"
... ...
>>> gmt1 = GMT1() ... def __repr__(self):
>>> # Daylight Saving Time ... return f"{self.__class__.__name__}()"
>>> dt1 = datetime(2006, 11, 21, 16, 30, tzinfo=gmt1) ...
>>> dt1.dst() >>> tz1 = KabulTz()
datetime.timedelta(0) >>> # Datetime before the change
>>> dt1.utcoffset() >>> dt1 = datetime(1900, 11, 21, 16, 30, tzinfo=tz1)
datetime.timedelta(seconds=3600) >>> print(dt1.utcoffset())
>>> dt2 = datetime(2006, 6, 14, 13, 0, tzinfo=gmt1) 4:00:00
>>> dt2.dst() >>> # Datetime after the change
datetime.timedelta(seconds=3600) >>> dt2 = datetime(2006, 6, 14, 13, 0, tzinfo=tz1)
>>> dt2.utcoffset() >>> print(dt2.utcoffset())
datetime.timedelta(seconds=7200) 4:30:00
>>> # Convert datetime to another time zone >>> # Convert datetime to another time zone
>>> dt3 = dt2.astimezone(GMT2()) >>> dt3 = dt2.astimezone(timezone.utc)
>>> dt3 # doctest: +ELLIPSIS >>> dt3
datetime.datetime(2006, 6, 14, 14, 0, tzinfo=<GMT2 object at 0x...>) datetime.datetime(2006, 6, 14, 8, 30, tzinfo=datetime.timezone.utc)
>>> dt2 # doctest: +ELLIPSIS >>> dt2
datetime.datetime(2006, 6, 14, 13, 0, tzinfo=<GMT1 object at 0x...>) datetime.datetime(2006, 6, 14, 13, 0, tzinfo=KabulTz())
>>> dt2.utctimetuple() == dt3.utctimetuple() >>> dt2.utctimetuple() == dt3.utctimetuple()
True True
...@@ -1656,26 +1664,27 @@ Instance methods: ...@@ -1656,26 +1664,27 @@ Instance methods:
Example: Example:
>>> from datetime import time, tzinfo, timedelta >>> from datetime import time, tzinfo, timedelta
>>> class GMT1(tzinfo): >>> class TZ1(tzinfo):
... def utcoffset(self, dt): ... def utcoffset(self, dt):
... return timedelta(hours=1) ... return timedelta(hours=1)
... def dst(self, dt): ... def dst(self, dt):
... return timedelta(0) ... return timedelta(0)
... def tzname(self,dt): ... def tzname(self,dt):
... return "Europe/Prague" ... return "+01:00"
... def __repr__(self):
... return f"{self.__class__.__name__}()"
... ...
>>> t = time(12, 10, 30, tzinfo=GMT1()) >>> t = time(12, 10, 30, tzinfo=TZ1())
>>> t # doctest: +ELLIPSIS >>> t
datetime.time(12, 10, 30, tzinfo=<GMT1 object at 0x...>) datetime.time(12, 10, 30, tzinfo=TZ1())
>>> gmt = GMT1()
>>> t.isoformat() >>> t.isoformat()
'12:10:30+01:00' '12:10:30+01:00'
>>> t.dst() >>> t.dst()
datetime.timedelta(0) datetime.timedelta(0)
>>> t.tzname() >>> t.tzname()
'Europe/Prague' '+01:00'
>>> t.strftime("%H:%M:%S %Z") >>> t.strftime("%H:%M:%S %Z")
'12:10:30 Europe/Prague' '12:10:30 +01:00'
>>> 'The {} is {:%H:%M}.'.format("time", t) >>> 'The {} is {:%H:%M}.'.format("time", t)
'The time is 12:10.' 'The time is 12:10.'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment