diff env/lib/python3.7/site-packages/dateutil/tz/tz.py @ 5:9b1c78e6ba9c draft default tip

"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author shellac
date Mon, 01 Jun 2020 08:59:25 -0400
parents 79f47841a781
children
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/dateutil/tz/tz.py	Thu May 14 16:47:39 2020 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1849 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-This module offers timezone implementations subclassing the abstract
-:py:class:`datetime.tzinfo` type. There are classes to handle tzfile format
-files (usually are in :file:`/etc/localtime`, :file:`/usr/share/zoneinfo`,
-etc), TZ environment string (in all known formats), given ranges (with help
-from relative deltas), local machine timezone, fixed offset timezone, and UTC
-timezone.
-"""
-import datetime
-import struct
-import time
-import sys
-import os
-import bisect
-import weakref
-from collections import OrderedDict
-
-import six
-from six import string_types
-from six.moves import _thread
-from ._common import tzname_in_python2, _tzinfo
-from ._common import tzrangebase, enfold
-from ._common import _validate_fromutc_inputs
-
-from ._factories import _TzSingleton, _TzOffsetFactory
-from ._factories import _TzStrFactory
-try:
-    from .win import tzwin, tzwinlocal
-except ImportError:
-    tzwin = tzwinlocal = None
-
-# For warning about rounding tzinfo
-from warnings import warn
-
-ZERO = datetime.timedelta(0)
-EPOCH = datetime.datetime.utcfromtimestamp(0)
-EPOCHORDINAL = EPOCH.toordinal()
-
-
-@six.add_metaclass(_TzSingleton)
-class tzutc(datetime.tzinfo):
-    """
-    This is a tzinfo object that represents the UTC time zone.
-
-    **Examples:**
-
-    .. doctest::
-
-        >>> from datetime import *
-        >>> from dateutil.tz import *
-
-        >>> datetime.now()
-        datetime.datetime(2003, 9, 27, 9, 40, 1, 521290)
-
-        >>> datetime.now(tzutc())
-        datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc())
-
-        >>> datetime.now(tzutc()).tzname()
-        'UTC'
-
-    .. versionchanged:: 2.7.0
-        ``tzutc()`` is now a singleton, so the result of ``tzutc()`` will
-        always return the same object.
-
-        .. doctest::
-
-            >>> from dateutil.tz import tzutc, UTC
-            >>> tzutc() is tzutc()
-            True
-            >>> tzutc() is UTC
-            True
-    """
-    def utcoffset(self, dt):
-        return ZERO
-
-    def dst(self, dt):
-        return ZERO
-
-    @tzname_in_python2
-    def tzname(self, dt):
-        return "UTC"
-
-    def is_ambiguous(self, dt):
-        """
-        Whether or not the "wall time" of a given datetime is ambiguous in this
-        zone.
-
-        :param dt:
-            A :py:class:`datetime.datetime`, naive or time zone aware.
-
-
-        :return:
-            Returns ``True`` if ambiguous, ``False`` otherwise.
-
-        .. versionadded:: 2.6.0
-        """
-        return False
-
-    @_validate_fromutc_inputs
-    def fromutc(self, dt):
-        """
-        Fast track version of fromutc() returns the original ``dt`` object for
-        any valid :py:class:`datetime.datetime` object.
-        """
-        return dt
-
-    def __eq__(self, other):
-        if not isinstance(other, (tzutc, tzoffset)):
-            return NotImplemented
-
-        return (isinstance(other, tzutc) or
-                (isinstance(other, tzoffset) and other._offset == ZERO))
-
-    __hash__ = None
-
-    def __ne__(self, other):
-        return not (self == other)
-
-    def __repr__(self):
-        return "%s()" % self.__class__.__name__
-
-    __reduce__ = object.__reduce__
-
-
-#: Convenience constant providing a :class:`tzutc()` instance
-#:
-#: .. versionadded:: 2.7.0
-UTC = tzutc()
-
-
-@six.add_metaclass(_TzOffsetFactory)
-class tzoffset(datetime.tzinfo):
-    """
-    A simple class for representing a fixed offset from UTC.
-
-    :param name:
-        The timezone name, to be returned when ``tzname()`` is called.
-    :param offset:
-        The time zone offset in seconds, or (since version 2.6.0, represented
-        as a :py:class:`datetime.timedelta` object).
-    """
-    def __init__(self, name, offset):
-        self._name = name
-
-        try:
-            # Allow a timedelta
-            offset = offset.total_seconds()
-        except (TypeError, AttributeError):
-            pass
-
-        self._offset = datetime.timedelta(seconds=_get_supported_offset(offset))
-
-    def utcoffset(self, dt):
-        return self._offset
-
-    def dst(self, dt):
-        return ZERO
-
-    @tzname_in_python2
-    def tzname(self, dt):
-        return self._name
-
-    @_validate_fromutc_inputs
-    def fromutc(self, dt):
-        return dt + self._offset
-
-    def is_ambiguous(self, dt):
-        """
-        Whether or not the "wall time" of a given datetime is ambiguous in this
-        zone.
-
-        :param dt:
-            A :py:class:`datetime.datetime`, naive or time zone aware.
-        :return:
-            Returns ``True`` if ambiguous, ``False`` otherwise.
-
-        .. versionadded:: 2.6.0
-        """
-        return False
-
-    def __eq__(self, other):
-        if not isinstance(other, tzoffset):
-            return NotImplemented
-
-        return self._offset == other._offset
-
-    __hash__ = None
-
-    def __ne__(self, other):
-        return not (self == other)
-
-    def __repr__(self):
-        return "%s(%s, %s)" % (self.__class__.__name__,
-                               repr(self._name),
-                               int(self._offset.total_seconds()))
-
-    __reduce__ = object.__reduce__
-
-
-class tzlocal(_tzinfo):
-    """
-    A :class:`tzinfo` subclass built around the ``time`` timezone functions.
-    """
-    def __init__(self):
-        super(tzlocal, self).__init__()
-
-        self._std_offset = datetime.timedelta(seconds=-time.timezone)
-        if time.daylight:
-            self._dst_offset = datetime.timedelta(seconds=-time.altzone)
-        else:
-            self._dst_offset = self._std_offset
-
-        self._dst_saved = self._dst_offset - self._std_offset
-        self._hasdst = bool(self._dst_saved)
-        self._tznames = tuple(time.tzname)
-
-    def utcoffset(self, dt):
-        if dt is None and self._hasdst:
-            return None
-
-        if self._isdst(dt):
-            return self._dst_offset
-        else:
-            return self._std_offset
-
-    def dst(self, dt):
-        if dt is None and self._hasdst:
-            return None
-
-        if self._isdst(dt):
-            return self._dst_offset - self._std_offset
-        else:
-            return ZERO
-
-    @tzname_in_python2
-    def tzname(self, dt):
-        return self._tznames[self._isdst(dt)]
-
-    def is_ambiguous(self, dt):
-        """
-        Whether or not the "wall time" of a given datetime is ambiguous in this
-        zone.
-
-        :param dt:
-            A :py:class:`datetime.datetime`, naive or time zone aware.
-
-
-        :return:
-            Returns ``True`` if ambiguous, ``False`` otherwise.
-
-        .. versionadded:: 2.6.0
-        """
-        naive_dst = self._naive_is_dst(dt)
-        return (not naive_dst and
-                (naive_dst != self._naive_is_dst(dt - self._dst_saved)))
-
-    def _naive_is_dst(self, dt):
-        timestamp = _datetime_to_timestamp(dt)
-        return time.localtime(timestamp + time.timezone).tm_isdst
-
-    def _isdst(self, dt, fold_naive=True):
-        # We can't use mktime here. It is unstable when deciding if
-        # the hour near to a change is DST or not.
-        #
-        # timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour,
-        #                         dt.minute, dt.second, dt.weekday(), 0, -1))
-        # return time.localtime(timestamp).tm_isdst
-        #
-        # The code above yields the following result:
-        #
-        # >>> import tz, datetime
-        # >>> t = tz.tzlocal()
-        # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
-        # 'BRDT'
-        # >>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname()
-        # 'BRST'
-        # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
-        # 'BRST'
-        # >>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname()
-        # 'BRDT'
-        # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
-        # 'BRDT'
-        #
-        # Here is a more stable implementation:
-        #
-        if not self._hasdst:
-            return False
-
-        # Check for ambiguous times:
-        dstval = self._naive_is_dst(dt)
-        fold = getattr(dt, 'fold', None)
-
-        if self.is_ambiguous(dt):
-            if fold is not None:
-                return not self._fold(dt)
-            else:
-                return True
-
-        return dstval
-
-    def __eq__(self, other):
-        if isinstance(other, tzlocal):
-            return (self._std_offset == other._std_offset and
-                    self._dst_offset == other._dst_offset)
-        elif isinstance(other, tzutc):
-            return (not self._hasdst and
-                    self._tznames[0] in {'UTC', 'GMT'} and
-                    self._std_offset == ZERO)
-        elif isinstance(other, tzoffset):
-            return (not self._hasdst and
-                    self._tznames[0] == other._name and
-                    self._std_offset == other._offset)
-        else:
-            return NotImplemented
-
-    __hash__ = None
-
-    def __ne__(self, other):
-        return not (self == other)
-
-    def __repr__(self):
-        return "%s()" % self.__class__.__name__
-
-    __reduce__ = object.__reduce__
-
-
-class _ttinfo(object):
-    __slots__ = ["offset", "delta", "isdst", "abbr",
-                 "isstd", "isgmt", "dstoffset"]
-
-    def __init__(self):
-        for attr in self.__slots__:
-            setattr(self, attr, None)
-
-    def __repr__(self):
-        l = []
-        for attr in self.__slots__:
-            value = getattr(self, attr)
-            if value is not None:
-                l.append("%s=%s" % (attr, repr(value)))
-        return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
-
-    def __eq__(self, other):
-        if not isinstance(other, _ttinfo):
-            return NotImplemented
-
-        return (self.offset == other.offset and
-                self.delta == other.delta and
-                self.isdst == other.isdst and
-                self.abbr == other.abbr and
-                self.isstd == other.isstd and
-                self.isgmt == other.isgmt and
-                self.dstoffset == other.dstoffset)
-
-    __hash__ = None
-
-    def __ne__(self, other):
-        return not (self == other)
-
-    def __getstate__(self):
-        state = {}
-        for name in self.__slots__:
-            state[name] = getattr(self, name, None)
-        return state
-
-    def __setstate__(self, state):
-        for name in self.__slots__:
-            if name in state:
-                setattr(self, name, state[name])
-
-
-class _tzfile(object):
-    """
-    Lightweight class for holding the relevant transition and time zone
-    information read from binary tzfiles.
-    """
-    attrs = ['trans_list', 'trans_list_utc', 'trans_idx', 'ttinfo_list',
-             'ttinfo_std', 'ttinfo_dst', 'ttinfo_before', 'ttinfo_first']
-
-    def __init__(self, **kwargs):
-        for attr in self.attrs:
-            setattr(self, attr, kwargs.get(attr, None))
-
-
-class tzfile(_tzinfo):
-    """
-    This is a ``tzinfo`` subclass that allows one to use the ``tzfile(5)``
-    format timezone files to extract current and historical zone information.
-
-    :param fileobj:
-        This can be an opened file stream or a file name that the time zone
-        information can be read from.
-
-    :param filename:
-        This is an optional parameter specifying the source of the time zone
-        information in the event that ``fileobj`` is a file object. If omitted
-        and ``fileobj`` is a file stream, this parameter will be set either to
-        ``fileobj``'s ``name`` attribute or to ``repr(fileobj)``.
-
-    See `Sources for Time Zone and Daylight Saving Time Data
-    <https://data.iana.org/time-zones/tz-link.html>`_ for more information.
-    Time zone files can be compiled from the `IANA Time Zone database files
-    <https://www.iana.org/time-zones>`_ with the `zic time zone compiler
-    <https://www.freebsd.org/cgi/man.cgi?query=zic&sektion=8>`_
-
-    .. note::
-
-        Only construct a ``tzfile`` directly if you have a specific timezone
-        file on disk that you want to read into a Python ``tzinfo`` object.
-        If you want to get a ``tzfile`` representing a specific IANA zone,
-        (e.g. ``'America/New_York'``), you should call
-        :func:`dateutil.tz.gettz` with the zone identifier.
-
-
-    **Examples:**
-
-    Using the US Eastern time zone as an example, we can see that a ``tzfile``
-    provides time zone information for the standard Daylight Saving offsets:
-
-    .. testsetup:: tzfile
-
-        from dateutil.tz import gettz
-        from datetime import datetime
-
-    .. doctest:: tzfile
-
-        >>> NYC = gettz('America/New_York')
-        >>> NYC
-        tzfile('/usr/share/zoneinfo/America/New_York')
-
-        >>> print(datetime(2016, 1, 3, tzinfo=NYC))     # EST
-        2016-01-03 00:00:00-05:00
-
-        >>> print(datetime(2016, 7, 7, tzinfo=NYC))     # EDT
-        2016-07-07 00:00:00-04:00
-
-
-    The ``tzfile`` structure contains a fully history of the time zone,
-    so historical dates will also have the right offsets. For example, before
-    the adoption of the UTC standards, New York used local solar  mean time:
-
-    .. doctest:: tzfile
-
-       >>> print(datetime(1901, 4, 12, tzinfo=NYC))    # LMT
-       1901-04-12 00:00:00-04:56
-
-    And during World War II, New York was on "Eastern War Time", which was a
-    state of permanent daylight saving time:
-
-    .. doctest:: tzfile
-
-        >>> print(datetime(1944, 2, 7, tzinfo=NYC))    # EWT
-        1944-02-07 00:00:00-04:00
-
-    """
-
-    def __init__(self, fileobj, filename=None):
-        super(tzfile, self).__init__()
-
-        file_opened_here = False
-        if isinstance(fileobj, string_types):
-            self._filename = fileobj
-            fileobj = open(fileobj, 'rb')
-            file_opened_here = True
-        elif filename is not None:
-            self._filename = filename
-        elif hasattr(fileobj, "name"):
-            self._filename = fileobj.name
-        else:
-            self._filename = repr(fileobj)
-
-        if fileobj is not None:
-            if not file_opened_here:
-                fileobj = _nullcontext(fileobj)
-
-            with fileobj as file_stream:
-                tzobj = self._read_tzfile(file_stream)
-
-            self._set_tzdata(tzobj)
-
-    def _set_tzdata(self, tzobj):
-        """ Set the time zone data of this object from a _tzfile object """
-        # Copy the relevant attributes over as private attributes
-        for attr in _tzfile.attrs:
-            setattr(self, '_' + attr, getattr(tzobj, attr))
-
-    def _read_tzfile(self, fileobj):
-        out = _tzfile()
-
-        # From tzfile(5):
-        #
-        # The time zone information files used by tzset(3)
-        # begin with the magic characters "TZif" to identify
-        # them as time zone information files, followed by
-        # sixteen bytes reserved for future use, followed by
-        # six four-byte values of type long, written in a
-        # ``standard'' byte order (the high-order  byte
-        # of the value is written first).
-        if fileobj.read(4).decode() != "TZif":
-            raise ValueError("magic not found")
-
-        fileobj.read(16)
-
-        (
-            # The number of UTC/local indicators stored in the file.
-            ttisgmtcnt,
-
-            # The number of standard/wall indicators stored in the file.
-            ttisstdcnt,
-
-            # The number of leap seconds for which data is
-            # stored in the file.
-            leapcnt,
-
-            # The number of "transition times" for which data
-            # is stored in the file.
-            timecnt,
-
-            # The number of "local time types" for which data
-            # is stored in the file (must not be zero).
-            typecnt,
-
-            # The  number  of  characters  of "time zone
-            # abbreviation strings" stored in the file.
-            charcnt,
-
-        ) = struct.unpack(">6l", fileobj.read(24))
-
-        # The above header is followed by tzh_timecnt four-byte
-        # values  of  type long,  sorted  in ascending order.
-        # These values are written in ``standard'' byte order.
-        # Each is used as a transition time (as  returned  by
-        # time(2)) at which the rules for computing local time
-        # change.
-
-        if timecnt:
-            out.trans_list_utc = list(struct.unpack(">%dl" % timecnt,
-                                                    fileobj.read(timecnt*4)))
-        else:
-            out.trans_list_utc = []
-
-        # Next come tzh_timecnt one-byte values of type unsigned
-        # char; each one tells which of the different types of
-        # ``local time'' types described in the file is associated
-        # with the same-indexed transition time. These values
-        # serve as indices into an array of ttinfo structures that
-        # appears next in the file.
-
-        if timecnt:
-            out.trans_idx = struct.unpack(">%dB" % timecnt,
-                                          fileobj.read(timecnt))
-        else:
-            out.trans_idx = []
-
-        # Each ttinfo structure is written as a four-byte value
-        # for tt_gmtoff  of  type long,  in  a  standard  byte
-        # order, followed  by a one-byte value for tt_isdst
-        # and a one-byte  value  for  tt_abbrind.   In  each
-        # structure, tt_gmtoff  gives  the  number  of
-        # seconds to be added to UTC, tt_isdst tells whether
-        # tm_isdst should be set by  localtime(3),  and
-        # tt_abbrind serves  as an index into the array of
-        # time zone abbreviation characters that follow the
-        # ttinfo structure(s) in the file.
-
-        ttinfo = []
-
-        for i in range(typecnt):
-            ttinfo.append(struct.unpack(">lbb", fileobj.read(6)))
-
-        abbr = fileobj.read(charcnt).decode()
-
-        # Then there are tzh_leapcnt pairs of four-byte
-        # values, written in  standard byte  order;  the
-        # first  value  of  each pair gives the time (as
-        # returned by time(2)) at which a leap second
-        # occurs;  the  second  gives the  total  number of
-        # leap seconds to be applied after the given time.
-        # The pairs of values are sorted in ascending order
-        # by time.
-
-        # Not used, for now (but seek for correct file position)
-        if leapcnt:
-            fileobj.seek(leapcnt * 8, os.SEEK_CUR)
-
-        # Then there are tzh_ttisstdcnt standard/wall
-        # indicators, each stored as a one-byte value;
-        # they tell whether the transition times associated
-        # with local time types were specified as standard
-        # time or wall clock time, and are used when
-        # a time zone file is used in handling POSIX-style
-        # time zone environment variables.
-
-        if ttisstdcnt:
-            isstd = struct.unpack(">%db" % ttisstdcnt,
-                                  fileobj.read(ttisstdcnt))
-
-        # Finally, there are tzh_ttisgmtcnt UTC/local
-        # indicators, each stored as a one-byte value;
-        # they tell whether the transition times associated
-        # with local time types were specified as UTC or
-        # local time, and are used when a time zone file
-        # is used in handling POSIX-style time zone envi-
-        # ronment variables.
-
-        if ttisgmtcnt:
-            isgmt = struct.unpack(">%db" % ttisgmtcnt,
-                                  fileobj.read(ttisgmtcnt))
-
-        # Build ttinfo list
-        out.ttinfo_list = []
-        for i in range(typecnt):
-            gmtoff, isdst, abbrind = ttinfo[i]
-            gmtoff = _get_supported_offset(gmtoff)
-            tti = _ttinfo()
-            tti.offset = gmtoff
-            tti.dstoffset = datetime.timedelta(0)
-            tti.delta = datetime.timedelta(seconds=gmtoff)
-            tti.isdst = isdst
-            tti.abbr = abbr[abbrind:abbr.find('\x00', abbrind)]
-            tti.isstd = (ttisstdcnt > i and isstd[i] != 0)
-            tti.isgmt = (ttisgmtcnt > i and isgmt[i] != 0)
-            out.ttinfo_list.append(tti)
-
-        # Replace ttinfo indexes for ttinfo objects.
-        out.trans_idx = [out.ttinfo_list[idx] for idx in out.trans_idx]
-
-        # Set standard, dst, and before ttinfos. before will be
-        # used when a given time is before any transitions,
-        # and will be set to the first non-dst ttinfo, or to
-        # the first dst, if all of them are dst.
-        out.ttinfo_std = None
-        out.ttinfo_dst = None
-        out.ttinfo_before = None
-        if out.ttinfo_list:
-            if not out.trans_list_utc:
-                out.ttinfo_std = out.ttinfo_first = out.ttinfo_list[0]
-            else:
-                for i in range(timecnt-1, -1, -1):
-                    tti = out.trans_idx[i]
-                    if not out.ttinfo_std and not tti.isdst:
-                        out.ttinfo_std = tti
-                    elif not out.ttinfo_dst and tti.isdst:
-                        out.ttinfo_dst = tti
-
-                    if out.ttinfo_std and out.ttinfo_dst:
-                        break
-                else:
-                    if out.ttinfo_dst and not out.ttinfo_std:
-                        out.ttinfo_std = out.ttinfo_dst
-
-                for tti in out.ttinfo_list:
-                    if not tti.isdst:
-                        out.ttinfo_before = tti
-                        break
-                else:
-                    out.ttinfo_before = out.ttinfo_list[0]
-
-        # Now fix transition times to become relative to wall time.
-        #
-        # I'm not sure about this. In my tests, the tz source file
-        # is setup to wall time, and in the binary file isstd and
-        # isgmt are off, so it should be in wall time. OTOH, it's
-        # always in gmt time. Let me know if you have comments
-        # about this.
-        lastdst = None
-        lastoffset = None
-        lastdstoffset = None
-        lastbaseoffset = None
-        out.trans_list = []
-
-        for i, tti in enumerate(out.trans_idx):
-            offset = tti.offset
-            dstoffset = 0
-
-            if lastdst is not None:
-                if tti.isdst:
-                    if not lastdst:
-                        dstoffset = offset - lastoffset
-
-                    if not dstoffset and lastdstoffset:
-                        dstoffset = lastdstoffset
-
-                    tti.dstoffset = datetime.timedelta(seconds=dstoffset)
-                    lastdstoffset = dstoffset
-
-            # If a time zone changes its base offset during a DST transition,
-            # then you need to adjust by the previous base offset to get the
-            # transition time in local time. Otherwise you use the current
-            # base offset. Ideally, I would have some mathematical proof of
-            # why this is true, but I haven't really thought about it enough.
-            baseoffset = offset - dstoffset
-            adjustment = baseoffset
-            if (lastbaseoffset is not None and baseoffset != lastbaseoffset
-                    and tti.isdst != lastdst):
-                # The base DST has changed
-                adjustment = lastbaseoffset
-
-            lastdst = tti.isdst
-            lastoffset = offset
-            lastbaseoffset = baseoffset
-
-            out.trans_list.append(out.trans_list_utc[i] + adjustment)
-
-        out.trans_idx = tuple(out.trans_idx)
-        out.trans_list = tuple(out.trans_list)
-        out.trans_list_utc = tuple(out.trans_list_utc)
-
-        return out
-
-    def _find_last_transition(self, dt, in_utc=False):
-        # If there's no list, there are no transitions to find
-        if not self._trans_list:
-            return None
-
-        timestamp = _datetime_to_timestamp(dt)
-
-        # Find where the timestamp fits in the transition list - if the
-        # timestamp is a transition time, it's part of the "after" period.
-        trans_list = self._trans_list_utc if in_utc else self._trans_list
-        idx = bisect.bisect_right(trans_list, timestamp)
-
-        # We want to know when the previous transition was, so subtract off 1
-        return idx - 1
-
-    def _get_ttinfo(self, idx):
-        # For no list or after the last transition, default to _ttinfo_std
-        if idx is None or (idx + 1) >= len(self._trans_list):
-            return self._ttinfo_std
-
-        # If there is a list and the time is before it, return _ttinfo_before
-        if idx < 0:
-            return self._ttinfo_before
-
-        return self._trans_idx[idx]
-
-    def _find_ttinfo(self, dt):
-        idx = self._resolve_ambiguous_time(dt)
-
-        return self._get_ttinfo(idx)
-
-    def fromutc(self, dt):
-        """
-        The ``tzfile`` implementation of :py:func:`datetime.tzinfo.fromutc`.
-
-        :param dt:
-            A :py:class:`datetime.datetime` object.
-
-        :raises TypeError:
-            Raised if ``dt`` is not a :py:class:`datetime.datetime` object.
-
-        :raises ValueError:
-            Raised if this is called with a ``dt`` which does not have this
-            ``tzinfo`` attached.
-
-        :return:
-            Returns a :py:class:`datetime.datetime` object representing the
-            wall time in ``self``'s time zone.
-        """
-        # These isinstance checks are in datetime.tzinfo, so we'll preserve
-        # them, even if we don't care about duck typing.
-        if not isinstance(dt, datetime.datetime):
-            raise TypeError("fromutc() requires a datetime argument")
-
-        if dt.tzinfo is not self:
-            raise ValueError("dt.tzinfo is not self")
-
-        # First treat UTC as wall time and get the transition we're in.
-        idx = self._find_last_transition(dt, in_utc=True)
-        tti = self._get_ttinfo(idx)
-
-        dt_out = dt + datetime.timedelta(seconds=tti.offset)
-
-        fold = self.is_ambiguous(dt_out, idx=idx)
-
-        return enfold(dt_out, fold=int(fold))
-
-    def is_ambiguous(self, dt, idx=None):
-        """
-        Whether or not the "wall time" of a given datetime is ambiguous in this
-        zone.
-
-        :param dt:
-            A :py:class:`datetime.datetime`, naive or time zone aware.
-
-
-        :return:
-            Returns ``True`` if ambiguous, ``False`` otherwise.
-
-        .. versionadded:: 2.6.0
-        """
-        if idx is None:
-            idx = self._find_last_transition(dt)
-
-        # Calculate the difference in offsets from current to previous
-        timestamp = _datetime_to_timestamp(dt)
-        tti = self._get_ttinfo(idx)
-
-        if idx is None or idx <= 0:
-            return False
-
-        od = self._get_ttinfo(idx - 1).offset - tti.offset
-        tt = self._trans_list[idx]          # Transition time
-
-        return timestamp < tt + od
-
-    def _resolve_ambiguous_time(self, dt):
-        idx = self._find_last_transition(dt)
-
-        # If we have no transitions, return the index
-        _fold = self._fold(dt)
-        if idx is None or idx == 0:
-            return idx
-
-        # If it's ambiguous and we're in a fold, shift to a different index.
-        idx_offset = int(not _fold and self.is_ambiguous(dt, idx))
-
-        return idx - idx_offset
-
-    def utcoffset(self, dt):
-        if dt is None:
-            return None
-
-        if not self._ttinfo_std:
-            return ZERO
-
-        return self._find_ttinfo(dt).delta
-
-    def dst(self, dt):
-        if dt is None:
-            return None
-
-        if not self._ttinfo_dst:
-            return ZERO
-
-        tti = self._find_ttinfo(dt)
-
-        if not tti.isdst:
-            return ZERO
-
-        # The documentation says that utcoffset()-dst() must
-        # be constant for every dt.
-        return tti.dstoffset
-
-    @tzname_in_python2
-    def tzname(self, dt):
-        if not self._ttinfo_std or dt is None:
-            return None
-        return self._find_ttinfo(dt).abbr
-
-    def __eq__(self, other):
-        if not isinstance(other, tzfile):
-            return NotImplemented
-        return (self._trans_list == other._trans_list and
-                self._trans_idx == other._trans_idx and
-                self._ttinfo_list == other._ttinfo_list)
-
-    __hash__ = None
-
-    def __ne__(self, other):
-        return not (self == other)
-
-    def __repr__(self):
-        return "%s(%s)" % (self.__class__.__name__, repr(self._filename))
-
-    def __reduce__(self):
-        return self.__reduce_ex__(None)
-
-    def __reduce_ex__(self, protocol):
-        return (self.__class__, (None, self._filename), self.__dict__)
-
-
-class tzrange(tzrangebase):
-    """
-    The ``tzrange`` object is a time zone specified by a set of offsets and
-    abbreviations, equivalent to the way the ``TZ`` variable can be specified
-    in POSIX-like systems, but using Python delta objects to specify DST
-    start, end and offsets.
-
-    :param stdabbr:
-        The abbreviation for standard time (e.g. ``'EST'``).
-
-    :param stdoffset:
-        An integer or :class:`datetime.timedelta` object or equivalent
-        specifying the base offset from UTC.
-
-        If unspecified, +00:00 is used.
-
-    :param dstabbr:
-        The abbreviation for DST / "Summer" time (e.g. ``'EDT'``).
-
-        If specified, with no other DST information, DST is assumed to occur
-        and the default behavior or ``dstoffset``, ``start`` and ``end`` is
-        used. If unspecified and no other DST information is specified, it
-        is assumed that this zone has no DST.
-
-        If this is unspecified and other DST information is *is* specified,
-        DST occurs in the zone but the time zone abbreviation is left
-        unchanged.
-
-    :param dstoffset:
-        A an integer or :class:`datetime.timedelta` object or equivalent
-        specifying the UTC offset during DST. If unspecified and any other DST
-        information is specified, it is assumed to be the STD offset +1 hour.
-
-    :param start:
-        A :class:`relativedelta.relativedelta` object or equivalent specifying
-        the time and time of year that daylight savings time starts. To
-        specify, for example, that DST starts at 2AM on the 2nd Sunday in
-        March, pass:
-
-            ``relativedelta(hours=2, month=3, day=1, weekday=SU(+2))``
-
-        If unspecified and any other DST information is specified, the default
-        value is 2 AM on the first Sunday in April.
-
-    :param end:
-        A :class:`relativedelta.relativedelta` object or equivalent
-        representing the time and time of year that daylight savings time
-        ends, with the same specification method as in ``start``. One note is
-        that this should point to the first time in the *standard* zone, so if
-        a transition occurs at 2AM in the DST zone and the clocks are set back
-        1 hour to 1AM, set the ``hours`` parameter to +1.
-
-
-    **Examples:**
-
-    .. testsetup:: tzrange
-
-        from dateutil.tz import tzrange, tzstr
-
-    .. doctest:: tzrange
-
-        >>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT")
-        True
-
-        >>> from dateutil.relativedelta import *
-        >>> range1 = tzrange("EST", -18000, "EDT")
-        >>> range2 = tzrange("EST", -18000, "EDT", -14400,
-        ...                  relativedelta(hours=+2, month=4, day=1,
-        ...                                weekday=SU(+1)),
-        ...                  relativedelta(hours=+1, month=10, day=31,
-        ...                                weekday=SU(-1)))
-        >>> tzstr('EST5EDT') == range1 == range2
-        True
-
-    """
-    def __init__(self, stdabbr, stdoffset=None,
-                 dstabbr=None, dstoffset=None,
-                 start=None, end=None):
-
-        global relativedelta
-        from dateutil import relativedelta
-
-        self._std_abbr = stdabbr
-        self._dst_abbr = dstabbr
-
-        try:
-            stdoffset = stdoffset.total_seconds()
-        except (TypeError, AttributeError):
-            pass
-
-        try:
-            dstoffset = dstoffset.total_seconds()
-        except (TypeError, AttributeError):
-            pass
-
-        if stdoffset is not None:
-            self._std_offset = datetime.timedelta(seconds=stdoffset)
-        else:
-            self._std_offset = ZERO
-
-        if dstoffset is not None:
-            self._dst_offset = datetime.timedelta(seconds=dstoffset)
-        elif dstabbr and stdoffset is not None:
-            self._dst_offset = self._std_offset + datetime.timedelta(hours=+1)
-        else:
-            self._dst_offset = ZERO
-
-        if dstabbr and start is None:
-            self._start_delta = relativedelta.relativedelta(
-                hours=+2, month=4, day=1, weekday=relativedelta.SU(+1))
-        else:
-            self._start_delta = start
-
-        if dstabbr and end is None:
-            self._end_delta = relativedelta.relativedelta(
-                hours=+1, month=10, day=31, weekday=relativedelta.SU(-1))
-        else:
-            self._end_delta = end
-
-        self._dst_base_offset_ = self._dst_offset - self._std_offset
-        self.hasdst = bool(self._start_delta)
-
-    def transitions(self, year):
-        """
-        For a given year, get the DST on and off transition times, expressed
-        always on the standard time side. For zones with no transitions, this
-        function returns ``None``.
-
-        :param year:
-            The year whose transitions you would like to query.
-
-        :return:
-            Returns a :class:`tuple` of :class:`datetime.datetime` objects,
-            ``(dston, dstoff)`` for zones with an annual DST transition, or
-            ``None`` for fixed offset zones.
-        """
-        if not self.hasdst:
-            return None
-
-        base_year = datetime.datetime(year, 1, 1)
-
-        start = base_year + self._start_delta
-        end = base_year + self._end_delta
-
-        return (start, end)
-
-    def __eq__(self, other):
-        if not isinstance(other, tzrange):
-            return NotImplemented
-
-        return (self._std_abbr == other._std_abbr and
-                self._dst_abbr == other._dst_abbr and
-                self._std_offset == other._std_offset and
-                self._dst_offset == other._dst_offset and
-                self._start_delta == other._start_delta and
-                self._end_delta == other._end_delta)
-
-    @property
-    def _dst_base_offset(self):
-        return self._dst_base_offset_
-
-
-@six.add_metaclass(_TzStrFactory)
-class tzstr(tzrange):
-    """
-    ``tzstr`` objects are time zone objects specified by a time-zone string as
-    it would be passed to a ``TZ`` variable on POSIX-style systems (see
-    the `GNU C Library: TZ Variable`_ for more details).
-
-    There is one notable exception, which is that POSIX-style time zones use an
-    inverted offset format, so normally ``GMT+3`` would be parsed as an offset
-    3 hours *behind* GMT. The ``tzstr`` time zone object will parse this as an
-    offset 3 hours *ahead* of GMT. If you would like to maintain the POSIX
-    behavior, pass a ``True`` value to ``posix_offset``.
-
-    The :class:`tzrange` object provides the same functionality, but is
-    specified using :class:`relativedelta.relativedelta` objects. rather than
-    strings.
-
-    :param s:
-        A time zone string in ``TZ`` variable format. This can be a
-        :class:`bytes` (2.x: :class:`str`), :class:`str` (2.x:
-        :class:`unicode`) or a stream emitting unicode characters
-        (e.g. :class:`StringIO`).
-
-    :param posix_offset:
-        Optional. If set to ``True``, interpret strings such as ``GMT+3`` or
-        ``UTC+3`` as being 3 hours *behind* UTC rather than ahead, per the
-        POSIX standard.
-
-    .. caution::
-
-        Prior to version 2.7.0, this function also supported time zones
-        in the format:
-
-            * ``EST5EDT,4,0,6,7200,10,0,26,7200,3600``
-            * ``EST5EDT,4,1,0,7200,10,-1,0,7200,3600``
-
-        This format is non-standard and has been deprecated; this function
-        will raise a :class:`DeprecatedTZFormatWarning` until
-        support is removed in a future version.
-
-    .. _`GNU C Library: TZ Variable`:
-        https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
-    """
-    def __init__(self, s, posix_offset=False):
-        global parser
-        from dateutil.parser import _parser as parser
-
-        self._s = s
-
-        res = parser._parsetz(s)
-        if res is None or res.any_unused_tokens:
-            raise ValueError("unknown string format")
-
-        # Here we break the compatibility with the TZ variable handling.
-        # GMT-3 actually *means* the timezone -3.
-        if res.stdabbr in ("GMT", "UTC") and not posix_offset:
-            res.stdoffset *= -1
-
-        # We must initialize it first, since _delta() needs
-        # _std_offset and _dst_offset set. Use False in start/end
-        # to avoid building it two times.
-        tzrange.__init__(self, res.stdabbr, res.stdoffset,
-                         res.dstabbr, res.dstoffset,
-                         start=False, end=False)
-
-        if not res.dstabbr:
-            self._start_delta = None
-            self._end_delta = None
-        else:
-            self._start_delta = self._delta(res.start)
-            if self._start_delta:
-                self._end_delta = self._delta(res.end, isend=1)
-
-        self.hasdst = bool(self._start_delta)
-
-    def _delta(self, x, isend=0):
-        from dateutil import relativedelta
-        kwargs = {}
-        if x.month is not None:
-            kwargs["month"] = x.month
-            if x.weekday is not None:
-                kwargs["weekday"] = relativedelta.weekday(x.weekday, x.week)
-                if x.week > 0:
-                    kwargs["day"] = 1
-                else:
-                    kwargs["day"] = 31
-            elif x.day:
-                kwargs["day"] = x.day
-        elif x.yday is not None:
-            kwargs["yearday"] = x.yday
-        elif x.jyday is not None:
-            kwargs["nlyearday"] = x.jyday
-        if not kwargs:
-            # Default is to start on first sunday of april, and end
-            # on last sunday of october.
-            if not isend:
-                kwargs["month"] = 4
-                kwargs["day"] = 1
-                kwargs["weekday"] = relativedelta.SU(+1)
-            else:
-                kwargs["month"] = 10
-                kwargs["day"] = 31
-                kwargs["weekday"] = relativedelta.SU(-1)
-        if x.time is not None:
-            kwargs["seconds"] = x.time
-        else:
-            # Default is 2AM.
-            kwargs["seconds"] = 7200
-        if isend:
-            # Convert to standard time, to follow the documented way
-            # of working with the extra hour. See the documentation
-            # of the tzinfo class.
-            delta = self._dst_offset - self._std_offset
-            kwargs["seconds"] -= delta.seconds + delta.days * 86400
-        return relativedelta.relativedelta(**kwargs)
-
-    def __repr__(self):
-        return "%s(%s)" % (self.__class__.__name__, repr(self._s))
-
-
-class _tzicalvtzcomp(object):
-    def __init__(self, tzoffsetfrom, tzoffsetto, isdst,
-                 tzname=None, rrule=None):
-        self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom)
-        self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto)
-        self.tzoffsetdiff = self.tzoffsetto - self.tzoffsetfrom
-        self.isdst = isdst
-        self.tzname = tzname
-        self.rrule = rrule
-
-
-class _tzicalvtz(_tzinfo):
-    def __init__(self, tzid, comps=[]):
-        super(_tzicalvtz, self).__init__()
-
-        self._tzid = tzid
-        self._comps = comps
-        self._cachedate = []
-        self._cachecomp = []
-        self._cache_lock = _thread.allocate_lock()
-
-    def _find_comp(self, dt):
-        if len(self._comps) == 1:
-            return self._comps[0]
-
-        dt = dt.replace(tzinfo=None)
-
-        try:
-            with self._cache_lock:
-                return self._cachecomp[self._cachedate.index(
-                    (dt, self._fold(dt)))]
-        except ValueError:
-            pass
-
-        lastcompdt = None
-        lastcomp = None
-
-        for comp in self._comps:
-            compdt = self._find_compdt(comp, dt)
-
-            if compdt and (not lastcompdt or lastcompdt < compdt):
-                lastcompdt = compdt
-                lastcomp = comp
-
-        if not lastcomp:
-            # RFC says nothing about what to do when a given
-            # time is before the first onset date. We'll look for the
-            # first standard component, or the first component, if
-            # none is found.
-            for comp in self._comps:
-                if not comp.isdst:
-                    lastcomp = comp
-                    break
-            else:
-                lastcomp = comp[0]
-
-        with self._cache_lock:
-            self._cachedate.insert(0, (dt, self._fold(dt)))
-            self._cachecomp.insert(0, lastcomp)
-
-            if len(self._cachedate) > 10:
-                self._cachedate.pop()
-                self._cachecomp.pop()
-
-        return lastcomp
-
-    def _find_compdt(self, comp, dt):
-        if comp.tzoffsetdiff < ZERO and self._fold(dt):
-            dt -= comp.tzoffsetdiff
-
-        compdt = comp.rrule.before(dt, inc=True)
-
-        return compdt
-
-    def utcoffset(self, dt):
-        if dt is None:
-            return None
-
-        return self._find_comp(dt).tzoffsetto
-
-    def dst(self, dt):
-        comp = self._find_comp(dt)
-        if comp.isdst:
-            return comp.tzoffsetdiff
-        else:
-            return ZERO
-
-    @tzname_in_python2
-    def tzname(self, dt):
-        return self._find_comp(dt).tzname
-
-    def __repr__(self):
-        return "<tzicalvtz %s>" % repr(self._tzid)
-
-    __reduce__ = object.__reduce__
-
-
-class tzical(object):
-    """
-    This object is designed to parse an iCalendar-style ``VTIMEZONE`` structure
-    as set out in `RFC 5545`_ Section 4.6.5 into one or more `tzinfo` objects.
-
-    :param `fileobj`:
-        A file or stream in iCalendar format, which should be UTF-8 encoded
-        with CRLF endings.
-
-    .. _`RFC 5545`: https://tools.ietf.org/html/rfc5545
-    """
-    def __init__(self, fileobj):
-        global rrule
-        from dateutil import rrule
-
-        if isinstance(fileobj, string_types):
-            self._s = fileobj
-            # ical should be encoded in UTF-8 with CRLF
-            fileobj = open(fileobj, 'r')
-        else:
-            self._s = getattr(fileobj, 'name', repr(fileobj))
-            fileobj = _nullcontext(fileobj)
-
-        self._vtz = {}
-
-        with fileobj as fobj:
-            self._parse_rfc(fobj.read())
-
-    def keys(self):
-        """
-        Retrieves the available time zones as a list.
-        """
-        return list(self._vtz.keys())
-
-    def get(self, tzid=None):
-        """
-        Retrieve a :py:class:`datetime.tzinfo` object by its ``tzid``.
-
-        :param tzid:
-            If there is exactly one time zone available, omitting ``tzid``
-            or passing :py:const:`None` value returns it. Otherwise a valid
-            key (which can be retrieved from :func:`keys`) is required.
-
-        :raises ValueError:
-            Raised if ``tzid`` is not specified but there are either more
-            or fewer than 1 zone defined.
-
-        :returns:
-            Returns either a :py:class:`datetime.tzinfo` object representing
-            the relevant time zone or :py:const:`None` if the ``tzid`` was
-            not found.
-        """
-        if tzid is None:
-            if len(self._vtz) == 0:
-                raise ValueError("no timezones defined")
-            elif len(self._vtz) > 1:
-                raise ValueError("more than one timezone available")
-            tzid = next(iter(self._vtz))
-
-        return self._vtz.get(tzid)
-
-    def _parse_offset(self, s):
-        s = s.strip()
-        if not s:
-            raise ValueError("empty offset")
-        if s[0] in ('+', '-'):
-            signal = (-1, +1)[s[0] == '+']
-            s = s[1:]
-        else:
-            signal = +1
-        if len(s) == 4:
-            return (int(s[:2]) * 3600 + int(s[2:]) * 60) * signal
-        elif len(s) == 6:
-            return (int(s[:2]) * 3600 + int(s[2:4]) * 60 + int(s[4:])) * signal
-        else:
-            raise ValueError("invalid offset: " + s)
-
-    def _parse_rfc(self, s):
-        lines = s.splitlines()
-        if not lines:
-            raise ValueError("empty string")
-
-        # Unfold
-        i = 0
-        while i < len(lines):
-            line = lines[i].rstrip()
-            if not line:
-                del lines[i]
-            elif i > 0 and line[0] == " ":
-                lines[i-1] += line[1:]
-                del lines[i]
-            else:
-                i += 1
-
-        tzid = None
-        comps = []
-        invtz = False
-        comptype = None
-        for line in lines:
-            if not line:
-                continue
-            name, value = line.split(':', 1)
-            parms = name.split(';')
-            if not parms:
-                raise ValueError("empty property name")
-            name = parms[0].upper()
-            parms = parms[1:]
-            if invtz:
-                if name == "BEGIN":
-                    if value in ("STANDARD", "DAYLIGHT"):
-                        # Process component
-                        pass
-                    else:
-                        raise ValueError("unknown component: "+value)
-                    comptype = value
-                    founddtstart = False
-                    tzoffsetfrom = None
-                    tzoffsetto = None
-                    rrulelines = []
-                    tzname = None
-                elif name == "END":
-                    if value == "VTIMEZONE":
-                        if comptype:
-                            raise ValueError("component not closed: "+comptype)
-                        if not tzid:
-                            raise ValueError("mandatory TZID not found")
-                        if not comps:
-                            raise ValueError(
-                                "at least one component is needed")
-                        # Process vtimezone
-                        self._vtz[tzid] = _tzicalvtz(tzid, comps)
-                        invtz = False
-                    elif value == comptype:
-                        if not founddtstart:
-                            raise ValueError("mandatory DTSTART not found")
-                        if tzoffsetfrom is None:
-                            raise ValueError(
-                                "mandatory TZOFFSETFROM not found")
-                        if tzoffsetto is None:
-                            raise ValueError(
-                                "mandatory TZOFFSETFROM not found")
-                        # Process component
-                        rr = None
-                        if rrulelines:
-                            rr = rrule.rrulestr("\n".join(rrulelines),
-                                                compatible=True,
-                                                ignoretz=True,
-                                                cache=True)
-                        comp = _tzicalvtzcomp(tzoffsetfrom, tzoffsetto,
-                                              (comptype == "DAYLIGHT"),
-                                              tzname, rr)
-                        comps.append(comp)
-                        comptype = None
-                    else:
-                        raise ValueError("invalid component end: "+value)
-                elif comptype:
-                    if name == "DTSTART":
-                        # DTSTART in VTIMEZONE takes a subset of valid RRULE
-                        # values under RFC 5545.
-                        for parm in parms:
-                            if parm != 'VALUE=DATE-TIME':
-                                msg = ('Unsupported DTSTART param in ' +
-                                       'VTIMEZONE: ' + parm)
-                                raise ValueError(msg)
-                        rrulelines.append(line)
-                        founddtstart = True
-                    elif name in ("RRULE", "RDATE", "EXRULE", "EXDATE"):
-                        rrulelines.append(line)
-                    elif name == "TZOFFSETFROM":
-                        if parms:
-                            raise ValueError(
-                                "unsupported %s parm: %s " % (name, parms[0]))
-                        tzoffsetfrom = self._parse_offset(value)
-                    elif name == "TZOFFSETTO":
-                        if parms:
-                            raise ValueError(
-                                "unsupported TZOFFSETTO parm: "+parms[0])
-                        tzoffsetto = self._parse_offset(value)
-                    elif name == "TZNAME":
-                        if parms:
-                            raise ValueError(
-                                "unsupported TZNAME parm: "+parms[0])
-                        tzname = value
-                    elif name == "COMMENT":
-                        pass
-                    else:
-                        raise ValueError("unsupported property: "+name)
-                else:
-                    if name == "TZID":
-                        if parms:
-                            raise ValueError(
-                                "unsupported TZID parm: "+parms[0])
-                        tzid = value
-                    elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"):
-                        pass
-                    else:
-                        raise ValueError("unsupported property: "+name)
-            elif name == "BEGIN" and value == "VTIMEZONE":
-                tzid = None
-                comps = []
-                invtz = True
-
-    def __repr__(self):
-        return "%s(%s)" % (self.__class__.__name__, repr(self._s))
-
-
-if sys.platform != "win32":
-    TZFILES = ["/etc/localtime", "localtime"]
-    TZPATHS = ["/usr/share/zoneinfo",
-               "/usr/lib/zoneinfo",
-               "/usr/share/lib/zoneinfo",
-               "/etc/zoneinfo"]
-else:
-    TZFILES = []
-    TZPATHS = []
-
-
-def __get_gettz():
-    tzlocal_classes = (tzlocal,)
-    if tzwinlocal is not None:
-        tzlocal_classes += (tzwinlocal,)
-
-    class GettzFunc(object):
-        """
-        Retrieve a time zone object from a string representation
-
-        This function is intended to retrieve the :py:class:`tzinfo` subclass
-        that best represents the time zone that would be used if a POSIX
-        `TZ variable`_ were set to the same value.
-
-        If no argument or an empty string is passed to ``gettz``, local time
-        is returned:
-
-        .. code-block:: python3
-
-            >>> gettz()
-            tzfile('/etc/localtime')
-
-        This function is also the preferred way to map IANA tz database keys
-        to :class:`tzfile` objects:
-
-        .. code-block:: python3
-
-            >>> gettz('Pacific/Kiritimati')
-            tzfile('/usr/share/zoneinfo/Pacific/Kiritimati')
-
-        On Windows, the standard is extended to include the Windows-specific
-        zone names provided by the operating system:
-
-        .. code-block:: python3
-
-            >>> gettz('Egypt Standard Time')
-            tzwin('Egypt Standard Time')
-
-        Passing a GNU ``TZ`` style string time zone specification returns a
-        :class:`tzstr` object:
-
-        .. code-block:: python3
-
-            >>> gettz('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3')
-            tzstr('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3')
-
-        :param name:
-            A time zone name (IANA, or, on Windows, Windows keys), location of
-            a ``tzfile(5)`` zoneinfo file or ``TZ`` variable style time zone
-            specifier. An empty string, no argument or ``None`` is interpreted
-            as local time.
-
-        :return:
-            Returns an instance of one of ``dateutil``'s :py:class:`tzinfo`
-            subclasses.
-
-        .. versionchanged:: 2.7.0
-
-            After version 2.7.0, any two calls to ``gettz`` using the same
-            input strings will return the same object:
-
-            .. code-block:: python3
-
-                >>> tz.gettz('America/Chicago') is tz.gettz('America/Chicago')
-                True
-
-            In addition to improving performance, this ensures that
-            `"same zone" semantics`_ are used for datetimes in the same zone.
-
-
-        .. _`TZ variable`:
-            https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
-
-        .. _`"same zone" semantics`:
-            https://blog.ganssle.io/articles/2018/02/aware-datetime-arithmetic.html
-        """
-        def __init__(self):
-
-            self.__instances = weakref.WeakValueDictionary()
-            self.__strong_cache_size = 8
-            self.__strong_cache = OrderedDict()
-            self._cache_lock = _thread.allocate_lock()
-
-        def __call__(self, name=None):
-            with self._cache_lock:
-                rv = self.__instances.get(name, None)
-
-                if rv is None:
-                    rv = self.nocache(name=name)
-                    if not (name is None
-                            or isinstance(rv, tzlocal_classes)
-                            or rv is None):
-                        # tzlocal is slightly more complicated than the other
-                        # time zone providers because it depends on environment
-                        # at construction time, so don't cache that.
-                        #
-                        # We also cannot store weak references to None, so we
-                        # will also not store that.
-                        self.__instances[name] = rv
-                    else:
-                        # No need for strong caching, return immediately
-                        return rv
-
-                self.__strong_cache[name] = self.__strong_cache.pop(name, rv)
-
-                if len(self.__strong_cache) > self.__strong_cache_size:
-                    self.__strong_cache.popitem(last=False)
-
-            return rv
-
-        def set_cache_size(self, size):
-            with self._cache_lock:
-                self.__strong_cache_size = size
-                while len(self.__strong_cache) > size:
-                    self.__strong_cache.popitem(last=False)
-
-        def cache_clear(self):
-            with self._cache_lock:
-                self.__instances = weakref.WeakValueDictionary()
-                self.__strong_cache.clear()
-
-        @staticmethod
-        def nocache(name=None):
-            """A non-cached version of gettz"""
-            tz = None
-            if not name:
-                try:
-                    name = os.environ["TZ"]
-                except KeyError:
-                    pass
-            if name is None or name == ":":
-                for filepath in TZFILES:
-                    if not os.path.isabs(filepath):
-                        filename = filepath
-                        for path in TZPATHS:
-                            filepath = os.path.join(path, filename)
-                            if os.path.isfile(filepath):
-                                break
-                        else:
-                            continue
-                    if os.path.isfile(filepath):
-                        try:
-                            tz = tzfile(filepath)
-                            break
-                        except (IOError, OSError, ValueError):
-                            pass
-                else:
-                    tz = tzlocal()
-            else:
-                try:
-                    if name.startswith(":"):
-                        name = name[1:]
-                except TypeError as e:
-                    if isinstance(name, bytes):
-                        new_msg = "gettz argument should be str, not bytes"
-                        six.raise_from(TypeError(new_msg), e)
-                    else:
-                        raise
-                if os.path.isabs(name):
-                    if os.path.isfile(name):
-                        tz = tzfile(name)
-                    else:
-                        tz = None
-                else:
-                    for path in TZPATHS:
-                        filepath = os.path.join(path, name)
-                        if not os.path.isfile(filepath):
-                            filepath = filepath.replace(' ', '_')
-                            if not os.path.isfile(filepath):
-                                continue
-                        try:
-                            tz = tzfile(filepath)
-                            break
-                        except (IOError, OSError, ValueError):
-                            pass
-                    else:
-                        tz = None
-                        if tzwin is not None:
-                            try:
-                                tz = tzwin(name)
-                            except (WindowsError, UnicodeEncodeError):
-                                # UnicodeEncodeError is for Python 2.7 compat
-                                tz = None
-
-                        if not tz:
-                            from dateutil.zoneinfo import get_zonefile_instance
-                            tz = get_zonefile_instance().get(name)
-
-                        if not tz:
-                            for c in name:
-                                # name is not a tzstr unless it has at least
-                                # one offset. For short values of "name", an
-                                # explicit for loop seems to be the fastest way
-                                # To determine if a string contains a digit
-                                if c in "0123456789":
-                                    try:
-                                        tz = tzstr(name)
-                                    except ValueError:
-                                        pass
-                                    break
-                            else:
-                                if name in ("GMT", "UTC"):
-                                    tz = UTC
-                                elif name in time.tzname:
-                                    tz = tzlocal()
-            return tz
-
-    return GettzFunc()
-
-
-gettz = __get_gettz()
-del __get_gettz
-
-
-def datetime_exists(dt, tz=None):
-    """
-    Given a datetime and a time zone, determine whether or not a given datetime
-    would fall in a gap.
-
-    :param dt:
-        A :class:`datetime.datetime` (whose time zone will be ignored if ``tz``
-        is provided.)
-
-    :param tz:
-        A :class:`datetime.tzinfo` with support for the ``fold`` attribute. If
-        ``None`` or not provided, the datetime's own time zone will be used.
-
-    :return:
-        Returns a boolean value whether or not the "wall time" exists in
-        ``tz``.
-
-    .. versionadded:: 2.7.0
-    """
-    if tz is None:
-        if dt.tzinfo is None:
-            raise ValueError('Datetime is naive and no time zone provided.')
-        tz = dt.tzinfo
-
-    dt = dt.replace(tzinfo=None)
-
-    # This is essentially a test of whether or not the datetime can survive
-    # a round trip to UTC.
-    dt_rt = dt.replace(tzinfo=tz).astimezone(UTC).astimezone(tz)
-    dt_rt = dt_rt.replace(tzinfo=None)
-
-    return dt == dt_rt
-
-
-def datetime_ambiguous(dt, tz=None):
-    """
-    Given a datetime and a time zone, determine whether or not a given datetime
-    is ambiguous (i.e if there are two times differentiated only by their DST
-    status).
-
-    :param dt:
-        A :class:`datetime.datetime` (whose time zone will be ignored if ``tz``
-        is provided.)
-
-    :param tz:
-        A :class:`datetime.tzinfo` with support for the ``fold`` attribute. If
-        ``None`` or not provided, the datetime's own time zone will be used.
-
-    :return:
-        Returns a boolean value whether or not the "wall time" is ambiguous in
-        ``tz``.
-
-    .. versionadded:: 2.6.0
-    """
-    if tz is None:
-        if dt.tzinfo is None:
-            raise ValueError('Datetime is naive and no time zone provided.')
-
-        tz = dt.tzinfo
-
-    # If a time zone defines its own "is_ambiguous" function, we'll use that.
-    is_ambiguous_fn = getattr(tz, 'is_ambiguous', None)
-    if is_ambiguous_fn is not None:
-        try:
-            return tz.is_ambiguous(dt)
-        except Exception:
-            pass
-
-    # If it doesn't come out and tell us it's ambiguous, we'll just check if
-    # the fold attribute has any effect on this particular date and time.
-    dt = dt.replace(tzinfo=tz)
-    wall_0 = enfold(dt, fold=0)
-    wall_1 = enfold(dt, fold=1)
-
-    same_offset = wall_0.utcoffset() == wall_1.utcoffset()
-    same_dst = wall_0.dst() == wall_1.dst()
-
-    return not (same_offset and same_dst)
-
-
-def resolve_imaginary(dt):
-    """
-    Given a datetime that may be imaginary, return an existing datetime.
-
-    This function assumes that an imaginary datetime represents what the
-    wall time would be in a zone had the offset transition not occurred, so
-    it will always fall forward by the transition's change in offset.
-
-    .. doctest::
-
-        >>> from dateutil import tz
-        >>> from datetime import datetime
-        >>> NYC = tz.gettz('America/New_York')
-        >>> print(tz.resolve_imaginary(datetime(2017, 3, 12, 2, 30, tzinfo=NYC)))
-        2017-03-12 03:30:00-04:00
-
-        >>> KIR = tz.gettz('Pacific/Kiritimati')
-        >>> print(tz.resolve_imaginary(datetime(1995, 1, 1, 12, 30, tzinfo=KIR)))
-        1995-01-02 12:30:00+14:00
-
-    As a note, :func:`datetime.astimezone` is guaranteed to produce a valid,
-    existing datetime, so a round-trip to and from UTC is sufficient to get
-    an extant datetime, however, this generally "falls back" to an earlier time
-    rather than falling forward to the STD side (though no guarantees are made
-    about this behavior).
-
-    :param dt:
-        A :class:`datetime.datetime` which may or may not exist.
-
-    :return:
-        Returns an existing :class:`datetime.datetime`. If ``dt`` was not
-        imaginary, the datetime returned is guaranteed to be the same object
-        passed to the function.
-
-    .. versionadded:: 2.7.0
-    """
-    if dt.tzinfo is not None and not datetime_exists(dt):
-
-        curr_offset = (dt + datetime.timedelta(hours=24)).utcoffset()
-        old_offset = (dt - datetime.timedelta(hours=24)).utcoffset()
-
-        dt += curr_offset - old_offset
-
-    return dt
-
-
-def _datetime_to_timestamp(dt):
-    """
-    Convert a :class:`datetime.datetime` object to an epoch timestamp in
-    seconds since January 1, 1970, ignoring the time zone.
-    """
-    return (dt.replace(tzinfo=None) - EPOCH).total_seconds()
-
-
-if sys.version_info >= (3, 6):
-    def _get_supported_offset(second_offset):
-        return second_offset
-else:
-    def _get_supported_offset(second_offset):
-        # For python pre-3.6, round to full-minutes if that's not the case.
-        # Python's datetime doesn't accept sub-minute timezones. Check
-        # http://python.org/sf/1447945 or https://bugs.python.org/issue5288
-        # for some information.
-        old_offset = second_offset
-        calculated_offset = 60 * ((second_offset + 30) // 60)
-        return calculated_offset
-
-
-try:
-    # Python 3.7 feature
-    from contextlib import nullcontext as _nullcontext
-except ImportError:
-    class _nullcontext(object):
-        """
-        Class for wrapping contexts so that they are passed through in a
-        with statement.
-        """
-        def __init__(self, context):
-            self.context = context
-
-        def __enter__(self):
-            return self.context
-
-        def __exit__(*args, **kwargs):
-            pass
-
-# vim:ts=4:sw=4:et