(root)/
Python-3.11.7/
Doc/
includes/
tzinfo_examples.py
       1  from datetime import tzinfo, timedelta, datetime
       2  
       3  ZERO = timedelta(0)
       4  HOUR = timedelta(hours=1)
       5  SECOND = timedelta(seconds=1)
       6  
       7  # A class capturing the platform's idea of local time.
       8  # (May result in wrong values on historical times in
       9  #  timezones where UTC offset and/or the DST rules had
      10  #  changed in the past.)
      11  import time as _time
      12  
      13  STDOFFSET = timedelta(seconds = -_time.timezone)
      14  if _time.daylight:
      15      DSTOFFSET = timedelta(seconds = -_time.altzone)
      16  else:
      17      DSTOFFSET = STDOFFSET
      18  
      19  DSTDIFF = DSTOFFSET - STDOFFSET
      20  
      21  class ESC[4;38;5;81mLocalTimezone(ESC[4;38;5;149mtzinfo):
      22  
      23      def fromutc(self, dt):
      24          assert dt.tzinfo is self
      25          stamp = (dt - datetime(1970, 1, 1, tzinfo=self)) // SECOND
      26          args = _time.localtime(stamp)[:6]
      27          dst_diff = DSTDIFF // SECOND
      28          # Detect fold
      29          fold = (args == _time.localtime(stamp - dst_diff))
      30          return datetime(*args, microsecond=dt.microsecond,
      31                          tzinfo=self, fold=fold)
      32  
      33      def utcoffset(self, dt):
      34          if self._isdst(dt):
      35              return DSTOFFSET
      36          else:
      37              return STDOFFSET
      38  
      39      def dst(self, dt):
      40          if self._isdst(dt):
      41              return DSTDIFF
      42          else:
      43              return ZERO
      44  
      45      def tzname(self, dt):
      46          return _time.tzname[self._isdst(dt)]
      47  
      48      def _isdst(self, dt):
      49          tt = (dt.year, dt.month, dt.day,
      50                dt.hour, dt.minute, dt.second,
      51                dt.weekday(), 0, 0)
      52          stamp = _time.mktime(tt)
      53          tt = _time.localtime(stamp)
      54          return tt.tm_isdst > 0
      55  
      56  Local = LocalTimezone()
      57  
      58  
      59  # A complete implementation of current DST rules for major US time zones.
      60  
      61  def first_sunday_on_or_after(dt):
      62      days_to_go = 6 - dt.weekday()
      63      if days_to_go:
      64          dt += timedelta(days_to_go)
      65      return dt
      66  
      67  
      68  # US DST Rules
      69  #
      70  # This is a simplified (i.e., wrong for a few cases) set of rules for US
      71  # DST start and end times. For a complete and up-to-date set of DST rules
      72  # and timezone definitions, visit the Olson Database (or try pytz):
      73  # http://www.twinsun.com/tz/tz-link.htm
      74  # https://sourceforge.net/projects/pytz/ (might not be up-to-date)
      75  #
      76  # In the US, since 2007, DST starts at 2am (standard time) on the second
      77  # Sunday in March, which is the first Sunday on or after Mar 8.
      78  DSTSTART_2007 = datetime(1, 3, 8, 2)
      79  # and ends at 2am (DST time) on the first Sunday of Nov.
      80  DSTEND_2007 = datetime(1, 11, 1, 2)
      81  # From 1987 to 2006, DST used to start at 2am (standard time) on the first
      82  # Sunday in April and to end at 2am (DST time) on the last
      83  # Sunday of October, which is the first Sunday on or after Oct 25.
      84  DSTSTART_1987_2006 = datetime(1, 4, 1, 2)
      85  DSTEND_1987_2006 = datetime(1, 10, 25, 2)
      86  # From 1967 to 1986, DST used to start at 2am (standard time) on the last
      87  # Sunday in April (the one on or after April 24) and to end at 2am (DST time)
      88  # on the last Sunday of October, which is the first Sunday
      89  # on or after Oct 25.
      90  DSTSTART_1967_1986 = datetime(1, 4, 24, 2)
      91  DSTEND_1967_1986 = DSTEND_1987_2006
      92  
      93  def us_dst_range(year):
      94      # Find start and end times for US DST. For years before 1967, return
      95      # start = end for no DST.
      96      if 2006 < year:
      97          dststart, dstend = DSTSTART_2007, DSTEND_2007
      98      elif 1986 < year < 2007:
      99          dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006
     100      elif 1966 < year < 1987:
     101          dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986
     102      else:
     103          return (datetime(year, 1, 1), ) * 2
     104  
     105      start = first_sunday_on_or_after(dststart.replace(year=year))
     106      end = first_sunday_on_or_after(dstend.replace(year=year))
     107      return start, end
     108  
     109  
     110  class ESC[4;38;5;81mUSTimeZone(ESC[4;38;5;149mtzinfo):
     111  
     112      def __init__(self, hours, reprname, stdname, dstname):
     113          self.stdoffset = timedelta(hours=hours)
     114          self.reprname = reprname
     115          self.stdname = stdname
     116          self.dstname = dstname
     117  
     118      def __repr__(self):
     119          return self.reprname
     120  
     121      def tzname(self, dt):
     122          if self.dst(dt):
     123              return self.dstname
     124          else:
     125              return self.stdname
     126  
     127      def utcoffset(self, dt):
     128          return self.stdoffset + self.dst(dt)
     129  
     130      def dst(self, dt):
     131          if dt is None or dt.tzinfo is None:
     132              # An exception may be sensible here, in one or both cases.
     133              # It depends on how you want to treat them.  The default
     134              # fromutc() implementation (called by the default astimezone()
     135              # implementation) passes a datetime with dt.tzinfo is self.
     136              return ZERO
     137          assert dt.tzinfo is self
     138          start, end = us_dst_range(dt.year)
     139          # Can't compare naive to aware objects, so strip the timezone from
     140          # dt first.
     141          dt = dt.replace(tzinfo=None)
     142          if start + HOUR <= dt < end - HOUR:
     143              # DST is in effect.
     144              return HOUR
     145          if end - HOUR <= dt < end:
     146              # Fold (an ambiguous hour): use dt.fold to disambiguate.
     147              return ZERO if dt.fold else HOUR
     148          if start <= dt < start + HOUR:
     149              # Gap (a non-existent hour): reverse the fold rule.
     150              return HOUR if dt.fold else ZERO
     151          # DST is off.
     152          return ZERO
     153  
     154      def fromutc(self, dt):
     155          assert dt.tzinfo is self
     156          start, end = us_dst_range(dt.year)
     157          start = start.replace(tzinfo=self)
     158          end = end.replace(tzinfo=self)
     159          std_time = dt + self.stdoffset
     160          dst_time = std_time + HOUR
     161          if end <= dst_time < end + HOUR:
     162              # Repeated hour
     163              return std_time.replace(fold=1)
     164          if std_time < start or dst_time >= end:
     165              # Standard time
     166              return std_time
     167          if start <= std_time < end - HOUR:
     168              # Daylight saving time
     169              return dst_time
     170  
     171  
     172  Eastern  = USTimeZone(-5, "Eastern",  "EST", "EDT")
     173  Central  = USTimeZone(-6, "Central",  "CST", "CDT")
     174  Mountain = USTimeZone(-7, "Mountain", "MST", "MDT")
     175  Pacific  = USTimeZone(-8, "Pacific",  "PST", "PDT")