Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
tz.py1850 linesDownload Raw Back to tz
1# -*- coding: utf-8 -*-2"""3This module offers timezone implementations subclassing the abstract4:py:class:`datetime.tzinfo` type. There are classes to handle tzfile format5files (usually are in :file:`/etc/localtime`, :file:`/usr/share/zoneinfo`,6etc), TZ environment string (in all known formats), given ranges (with help7from relative deltas), local machine timezone, fixed offset timezone, and UTC8timezone.9"""10import datetime11import struct12import time13import sys14import os15import bisect16import weakref17from collections import OrderedDict18 19import six20from six import string_types21from six.moves import _thread22from ._common import tzname_in_python2, _tzinfo23from ._common import tzrangebase, enfold24from ._common import _validate_fromutc_inputs25 26from ._factories import _TzSingleton, _TzOffsetFactory27from ._factories import _TzStrFactory28try:29    from .win import tzwin, tzwinlocal30except ImportError:31    tzwin = tzwinlocal = None32 33# For warning about rounding tzinfo34from warnings import warn35 36ZERO = datetime.timedelta(0)37EPOCH = datetime.datetime(1970, 1, 1, 0, 0)38EPOCHORDINAL = EPOCH.toordinal()39 40 41@six.add_metaclass(_TzSingleton)42class tzutc(datetime.tzinfo):43    """44    This is a tzinfo object that represents the UTC time zone.45 46    **Examples:**47 48    .. doctest::49 50        >>> from datetime import *51        >>> from dateutil.tz import *52 53        >>> datetime.now()54        datetime.datetime(2003, 9, 27, 9, 40, 1, 521290)55 56        >>> datetime.now(tzutc())57        datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc())58 59        >>> datetime.now(tzutc()).tzname()60        'UTC'61 62    .. versionchanged:: 2.7.063        ``tzutc()`` is now a singleton, so the result of ``tzutc()`` will64        always return the same object.65 66        .. doctest::67 68            >>> from dateutil.tz import tzutc, UTC69            >>> tzutc() is tzutc()70            True71            >>> tzutc() is UTC72            True73    """74    def utcoffset(self, dt):75        return ZERO76 77    def dst(self, dt):78        return ZERO79 80    @tzname_in_python281    def tzname(self, dt):82        return "UTC"83 84    def is_ambiguous(self, dt):85        """86        Whether or not the "wall time" of a given datetime is ambiguous in this87        zone.88 89        :param dt:90            A :py:class:`datetime.datetime`, naive or time zone aware.91 92 93        :return:94            Returns ``True`` if ambiguous, ``False`` otherwise.95 96        .. versionadded:: 2.6.097        """98        return False99 100    @_validate_fromutc_inputs101    def fromutc(self, dt):102        """103        Fast track version of fromutc() returns the original ``dt`` object for104        any valid :py:class:`datetime.datetime` object.105        """106        return dt107 108    def __eq__(self, other):109        if not isinstance(other, (tzutc, tzoffset)):110            return NotImplemented111 112        return (isinstance(other, tzutc) or113                (isinstance(other, tzoffset) and other._offset == ZERO))114 115    __hash__ = None116 117    def __ne__(self, other):118        return not (self == other)119 120    def __repr__(self):121        return "%s()" % self.__class__.__name__122 123    __reduce__ = object.__reduce__124 125 126#: Convenience constant providing a :class:`tzutc()` instance127#:128#: .. versionadded:: 2.7.0129UTC = tzutc()130 131 132@six.add_metaclass(_TzOffsetFactory)133class tzoffset(datetime.tzinfo):134    """135    A simple class for representing a fixed offset from UTC.136 137    :param name:138        The timezone name, to be returned when ``tzname()`` is called.139    :param offset:140        The time zone offset in seconds, or (since version 2.6.0, represented141        as a :py:class:`datetime.timedelta` object).142    """143    def __init__(self, name, offset):144        self._name = name145 146        try:147            # Allow a timedelta148            offset = offset.total_seconds()149        except (TypeError, AttributeError):150            pass151 152        self._offset = datetime.timedelta(seconds=_get_supported_offset(offset))153 154    def utcoffset(self, dt):155        return self._offset156 157    def dst(self, dt):158        return ZERO159 160    @tzname_in_python2161    def tzname(self, dt):162        return self._name163 164    @_validate_fromutc_inputs165    def fromutc(self, dt):166        return dt + self._offset167 168    def is_ambiguous(self, dt):169        """170        Whether or not the "wall time" of a given datetime is ambiguous in this171        zone.172 173        :param dt:174            A :py:class:`datetime.datetime`, naive or time zone aware.175        :return:176            Returns ``True`` if ambiguous, ``False`` otherwise.177 178        .. versionadded:: 2.6.0179        """180        return False181 182    def __eq__(self, other):183        if not isinstance(other, tzoffset):184            return NotImplemented185 186        return self._offset == other._offset187 188    __hash__ = None189 190    def __ne__(self, other):191        return not (self == other)192 193    def __repr__(self):194        return "%s(%s, %s)" % (self.__class__.__name__,195                               repr(self._name),196                               int(self._offset.total_seconds()))197 198    __reduce__ = object.__reduce__199 200 201class tzlocal(_tzinfo):202    """203    A :class:`tzinfo` subclass built around the ``time`` timezone functions.204    """205    def __init__(self):206        super(tzlocal, self).__init__()207 208        self._std_offset = datetime.timedelta(seconds=-time.timezone)209        if time.daylight:210            self._dst_offset = datetime.timedelta(seconds=-time.altzone)211        else:212            self._dst_offset = self._std_offset213 214        self._dst_saved = self._dst_offset - self._std_offset215        self._hasdst = bool(self._dst_saved)216        self._tznames = tuple(time.tzname)217 218    def utcoffset(self, dt):219        if dt is None and self._hasdst:220            return None221 222        if self._isdst(dt):223            return self._dst_offset224        else:225            return self._std_offset226 227    def dst(self, dt):228        if dt is None and self._hasdst:229            return None230 231        if self._isdst(dt):232            return self._dst_offset - self._std_offset233        else:234            return ZERO235 236    @tzname_in_python2237    def tzname(self, dt):238        return self._tznames[self._isdst(dt)]239 240    def is_ambiguous(self, dt):241        """242        Whether or not the "wall time" of a given datetime is ambiguous in this243        zone.244 245        :param dt:246            A :py:class:`datetime.datetime`, naive or time zone aware.247 248 249        :return:250            Returns ``True`` if ambiguous, ``False`` otherwise.251 252        .. versionadded:: 2.6.0253        """254        naive_dst = self._naive_is_dst(dt)255        return (not naive_dst and256                (naive_dst != self._naive_is_dst(dt - self._dst_saved)))257 258    def _naive_is_dst(self, dt):259        timestamp = _datetime_to_timestamp(dt)260        return time.localtime(timestamp + time.timezone).tm_isdst261 262    def _isdst(self, dt, fold_naive=True):263        # We can't use mktime here. It is unstable when deciding if264        # the hour near to a change is DST or not.265        #266        # timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour,267        #                         dt.minute, dt.second, dt.weekday(), 0, -1))268        # return time.localtime(timestamp).tm_isdst269        #270        # The code above yields the following result:271        #272        # >>> import tz, datetime273        # >>> t = tz.tzlocal()274        # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()275        # 'BRDT'276        # >>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname()277        # 'BRST'278        # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()279        # 'BRST'280        # >>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname()281        # 'BRDT'282        # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()283        # 'BRDT'284        #285        # Here is a more stable implementation:286        #287        if not self._hasdst:288            return False289 290        # Check for ambiguous times:291        dstval = self._naive_is_dst(dt)292        fold = getattr(dt, 'fold', None)293 294        if self.is_ambiguous(dt):295            if fold is not None:296                return not self._fold(dt)297            else:298                return True299 300        return dstval301 302    def __eq__(self, other):303        if isinstance(other, tzlocal):304            return (self._std_offset == other._std_offset and305                    self._dst_offset == other._dst_offset)306        elif isinstance(other, tzutc):307            return (not self._hasdst and308                    self._tznames[0] in {'UTC', 'GMT'} and309                    self._std_offset == ZERO)310        elif isinstance(other, tzoffset):311            return (not self._hasdst and312                    self._tznames[0] == other._name and313                    self._std_offset == other._offset)314        else:315            return NotImplemented316 317    __hash__ = None318 319    def __ne__(self, other):320        return not (self == other)321 322    def __repr__(self):323        return "%s()" % self.__class__.__name__324 325    __reduce__ = object.__reduce__326 327 328class _ttinfo(object):329    __slots__ = ["offset", "delta", "isdst", "abbr",330                 "isstd", "isgmt", "dstoffset"]331 332    def __init__(self):333        for attr in self.__slots__:334            setattr(self, attr, None)335 336    def __repr__(self):337        l = []338        for attr in self.__slots__:339            value = getattr(self, attr)340            if value is not None:341                l.append("%s=%s" % (attr, repr(value)))342        return "%s(%s)" % (self.__class__.__name__, ", ".join(l))343 344    def __eq__(self, other):345        if not isinstance(other, _ttinfo):346            return NotImplemented347 348        return (self.offset == other.offset and349                self.delta == other.delta and350                self.isdst == other.isdst and351                self.abbr == other.abbr and352                self.isstd == other.isstd and353                self.isgmt == other.isgmt and354                self.dstoffset == other.dstoffset)355 356    __hash__ = None357 358    def __ne__(self, other):359        return not (self == other)360 361    def __getstate__(self):362        state = {}363        for name in self.__slots__:364            state[name] = getattr(self, name, None)365        return state366 367    def __setstate__(self, state):368        for name in self.__slots__:369            if name in state:370                setattr(self, name, state[name])371 372 373class _tzfile(object):374    """375    Lightweight class for holding the relevant transition and time zone376    information read from binary tzfiles.377    """378    attrs = ['trans_list', 'trans_list_utc', 'trans_idx', 'ttinfo_list',379             'ttinfo_std', 'ttinfo_dst', 'ttinfo_before', 'ttinfo_first']380 381    def __init__(self, **kwargs):382        for attr in self.attrs:383            setattr(self, attr, kwargs.get(attr, None))384 385 386class tzfile(_tzinfo):387    """388    This is a ``tzinfo`` subclass that allows one to use the ``tzfile(5)``389    format timezone files to extract current and historical zone information.390 391    :param fileobj:392        This can be an opened file stream or a file name that the time zone393        information can be read from.394 395    :param filename:396        This is an optional parameter specifying the source of the time zone397        information in the event that ``fileobj`` is a file object. If omitted398        and ``fileobj`` is a file stream, this parameter will be set either to399        ``fileobj``'s ``name`` attribute or to ``repr(fileobj)``.400 401    See `Sources for Time Zone and Daylight Saving Time Data402    <https://data.iana.org/time-zones/tz-link.html>`_ for more information.403    Time zone files can be compiled from the `IANA Time Zone database files404    <https://www.iana.org/time-zones>`_ with the `zic time zone compiler405    <https://www.freebsd.org/cgi/man.cgi?query=zic&sektion=8>`_406 407    .. note::408 409        Only construct a ``tzfile`` directly if you have a specific timezone410        file on disk that you want to read into a Python ``tzinfo`` object.411        If you want to get a ``tzfile`` representing a specific IANA zone,412        (e.g. ``'America/New_York'``), you should call413        :func:`dateutil.tz.gettz` with the zone identifier.414 415 416    **Examples:**417 418    Using the US Eastern time zone as an example, we can see that a ``tzfile``419    provides time zone information for the standard Daylight Saving offsets:420 421    .. testsetup:: tzfile422 423        from dateutil.tz import gettz424        from datetime import datetime425 426    .. doctest:: tzfile427 428        >>> NYC = gettz('America/New_York')429        >>> NYC430        tzfile('/usr/share/zoneinfo/America/New_York')431 432        >>> print(datetime(2016, 1, 3, tzinfo=NYC))     # EST433        2016-01-03 00:00:00-05:00434 435        >>> print(datetime(2016, 7, 7, tzinfo=NYC))     # EDT436        2016-07-07 00:00:00-04:00437 438 439    The ``tzfile`` structure contains a fully history of the time zone,440    so historical dates will also have the right offsets. For example, before441    the adoption of the UTC standards, New York used local solar  mean time:442 443    .. doctest:: tzfile444 445       >>> print(datetime(1901, 4, 12, tzinfo=NYC))    # LMT446       1901-04-12 00:00:00-04:56447 448    And during World War II, New York was on "Eastern War Time", which was a449    state of permanent daylight saving time:450 451    .. doctest:: tzfile452 453        >>> print(datetime(1944, 2, 7, tzinfo=NYC))    # EWT454        1944-02-07 00:00:00-04:00455 456    """457 458    def __init__(self, fileobj, filename=None):459        super(tzfile, self).__init__()460 461        file_opened_here = False462        if isinstance(fileobj, string_types):463            self._filename = fileobj464            fileobj = open(fileobj, 'rb')465            file_opened_here = True466        elif filename is not None:467            self._filename = filename468        elif hasattr(fileobj, "name"):469            self._filename = fileobj.name470        else:471            self._filename = repr(fileobj)472 473        if fileobj is not None:474            if not file_opened_here:475                fileobj = _nullcontext(fileobj)476 477            with fileobj as file_stream:478                tzobj = self._read_tzfile(file_stream)479 480            self._set_tzdata(tzobj)481 482    def _set_tzdata(self, tzobj):483        """ Set the time zone data of this object from a _tzfile object """484        # Copy the relevant attributes over as private attributes485        for attr in _tzfile.attrs:486            setattr(self, '_' + attr, getattr(tzobj, attr))487 488    def _read_tzfile(self, fileobj):489        out = _tzfile()490 491        # From tzfile(5):492        #493        # The time zone information files used by tzset(3)494        # begin with the magic characters "TZif" to identify495        # them as time zone information files, followed by496        # sixteen bytes reserved for future use, followed by497        # six four-byte values of type long, written in a498        # ``standard'' byte order (the high-order  byte499        # of the value is written first).500        if fileobj.read(4).decode() != "TZif":501            raise ValueError("magic not found")502 503        fileobj.read(16)504 505        (506            # The number of UTC/local indicators stored in the file.507            ttisgmtcnt,508 509            # The number of standard/wall indicators stored in the file.510            ttisstdcnt,511 512            # The number of leap seconds for which data is513            # stored in the file.514            leapcnt,515 516            # The number of "transition times" for which data517            # is stored in the file.518            timecnt,519 520            # The number of "local time types" for which data521            # is stored in the file (must not be zero).522            typecnt,523 524            # The  number  of  characters  of "time zone525            # abbreviation strings" stored in the file.526            charcnt,527 528        ) = struct.unpack(">6l", fileobj.read(24))529 530        # The above header is followed by tzh_timecnt four-byte531        # values  of  type long,  sorted  in ascending order.532        # These values are written in ``standard'' byte order.533        # Each is used as a transition time (as  returned  by534        # time(2)) at which the rules for computing local time535        # change.536 537        if timecnt:538            out.trans_list_utc = list(struct.unpack(">%dl" % timecnt,539                                                    fileobj.read(timecnt*4)))540        else:541            out.trans_list_utc = []542 543        # Next come tzh_timecnt one-byte values of type unsigned544        # char; each one tells which of the different types of545        # ``local time'' types described in the file is associated546        # with the same-indexed transition time. These values547        # serve as indices into an array of ttinfo structures that548        # appears next in the file.549 550        if timecnt:551            out.trans_idx = struct.unpack(">%dB" % timecnt,552                                          fileobj.read(timecnt))553        else:554            out.trans_idx = []555 556        # Each ttinfo structure is written as a four-byte value557        # for tt_gmtoff  of  type long,  in  a  standard  byte558        # order, followed  by a one-byte value for tt_isdst559        # and a one-byte  value  for  tt_abbrind.   In  each560        # structure, tt_gmtoff  gives  the  number  of561        # seconds to be added to UTC, tt_isdst tells whether562        # tm_isdst should be set by  localtime(3),  and563        # tt_abbrind serves  as an index into the array of564        # time zone abbreviation characters that follow the565        # ttinfo structure(s) in the file.566 567        ttinfo = []568 569        for i in range(typecnt):570            ttinfo.append(struct.unpack(">lbb", fileobj.read(6)))571 572        abbr = fileobj.read(charcnt).decode()573 574        # Then there are tzh_leapcnt pairs of four-byte575        # values, written in  standard byte  order;  the576        # first  value  of  each pair gives the time (as577        # returned by time(2)) at which a leap second578        # occurs;  the  second  gives the  total  number of579        # leap seconds to be applied after the given time.580        # The pairs of values are sorted in ascending order581        # by time.582 583        # Not used, for now (but seek for correct file position)584        if leapcnt:585            fileobj.seek(leapcnt * 8, os.SEEK_CUR)586 587        # Then there are tzh_ttisstdcnt standard/wall588        # indicators, each stored as a one-byte value;589        # they tell whether the transition times associated590        # with local time types were specified as standard591        # time or wall clock time, and are used when592        # a time zone file is used in handling POSIX-style593        # time zone environment variables.594 595        if ttisstdcnt:596            isstd = struct.unpack(">%db" % ttisstdcnt,597                                  fileobj.read(ttisstdcnt))598 599        # Finally, there are tzh_ttisgmtcnt UTC/local600        # indicators, each stored as a one-byte value;601        # they tell whether the transition times associated602        # with local time types were specified as UTC or603        # local time, and are used when a time zone file604        # is used in handling POSIX-style time zone envi-605        # ronment variables.606 607        if ttisgmtcnt:608            isgmt = struct.unpack(">%db" % ttisgmtcnt,609                                  fileobj.read(ttisgmtcnt))610 611        # Build ttinfo list612        out.ttinfo_list = []613        for i in range(typecnt):614            gmtoff, isdst, abbrind = ttinfo[i]615            gmtoff = _get_supported_offset(gmtoff)616            tti = _ttinfo()617            tti.offset = gmtoff618            tti.dstoffset = datetime.timedelta(0)619            tti.delta = datetime.timedelta(seconds=gmtoff)620            tti.isdst = isdst621            tti.abbr = abbr[abbrind:abbr.find('\x00', abbrind)]622            tti.isstd = (ttisstdcnt > i and isstd[i] != 0)623            tti.isgmt = (ttisgmtcnt > i and isgmt[i] != 0)624            out.ttinfo_list.append(tti)625 626        # Replace ttinfo indexes for ttinfo objects.627        out.trans_idx = [out.ttinfo_list[idx] for idx in out.trans_idx]628 629        # Set standard, dst, and before ttinfos. before will be630        # used when a given time is before any transitions,631        # and will be set to the first non-dst ttinfo, or to632        # the first dst, if all of them are dst.633        out.ttinfo_std = None634        out.ttinfo_dst = None635        out.ttinfo_before = None636        if out.ttinfo_list:637            if not out.trans_list_utc:638                out.ttinfo_std = out.ttinfo_first = out.ttinfo_list[0]639            else:640                for i in range(timecnt-1, -1, -1):641                    tti = out.trans_idx[i]642                    if not out.ttinfo_std and not tti.isdst:643                        out.ttinfo_std = tti644                    elif not out.ttinfo_dst and tti.isdst:645                        out.ttinfo_dst = tti646 647                    if out.ttinfo_std and out.ttinfo_dst:648                        break649                else:650                    if out.ttinfo_dst and not out.ttinfo_std:651                        out.ttinfo_std = out.ttinfo_dst652 653                for tti in out.ttinfo_list:654                    if not tti.isdst:655                        out.ttinfo_before = tti656                        break657                else:658                    out.ttinfo_before = out.ttinfo_list[0]659 660        # Now fix transition times to become relative to wall time.661        #662        # I'm not sure about this. In my tests, the tz source file663        # is setup to wall time, and in the binary file isstd and664        # isgmt are off, so it should be in wall time. OTOH, it's665        # always in gmt time. Let me know if you have comments666        # about this.667        lastdst = None668        lastoffset = None669        lastdstoffset = None670        lastbaseoffset = None671        out.trans_list = []672 673        for i, tti in enumerate(out.trans_idx):674            offset = tti.offset675            dstoffset = 0676 677            if lastdst is not None:678                if tti.isdst:679                    if not lastdst:680                        dstoffset = offset - lastoffset681 682                    if not dstoffset and lastdstoffset:683                        dstoffset = lastdstoffset684 685                    tti.dstoffset = datetime.timedelta(seconds=dstoffset)686                    lastdstoffset = dstoffset687 688            # If a time zone changes its base offset during a DST transition,689            # then you need to adjust by the previous base offset to get the690            # transition time in local time. Otherwise you use the current691            # base offset. Ideally, I would have some mathematical proof of692            # why this is true, but I haven't really thought about it enough.693            baseoffset = offset - dstoffset694            adjustment = baseoffset695            if (lastbaseoffset is not None and baseoffset != lastbaseoffset696                    and tti.isdst != lastdst):697                # The base DST has changed698                adjustment = lastbaseoffset699 700            lastdst = tti.isdst701            lastoffset = offset702            lastbaseoffset = baseoffset703 704            out.trans_list.append(out.trans_list_utc[i] + adjustment)705 706        out.trans_idx = tuple(out.trans_idx)707        out.trans_list = tuple(out.trans_list)708        out.trans_list_utc = tuple(out.trans_list_utc)709 710        return out711 712    def _find_last_transition(self, dt, in_utc=False):713        # If there's no list, there are no transitions to find714        if not self._trans_list:715            return None716 717        timestamp = _datetime_to_timestamp(dt)718 719        # Find where the timestamp fits in the transition list - if the720        # timestamp is a transition time, it's part of the "after" period.721        trans_list = self._trans_list_utc if in_utc else self._trans_list722        idx = bisect.bisect_right(trans_list, timestamp)723 724        # We want to know when the previous transition was, so subtract off 1725        return idx - 1726 727    def _get_ttinfo(self, idx):728        # For no list or after the last transition, default to _ttinfo_std729        if idx is None or (idx + 1) >= len(self._trans_list):730            return self._ttinfo_std731 732        # If there is a list and the time is before it, return _ttinfo_before733        if idx < 0:734            return self._ttinfo_before735 736        return self._trans_idx[idx]737 738    def _find_ttinfo(self, dt):739        idx = self._resolve_ambiguous_time(dt)740 741        return self._get_ttinfo(idx)742 743    def fromutc(self, dt):744        """745        The ``tzfile`` implementation of :py:func:`datetime.tzinfo.fromutc`.746 747        :param dt:748            A :py:class:`datetime.datetime` object.749 750        :raises TypeError:751            Raised if ``dt`` is not a :py:class:`datetime.datetime` object.752 753        :raises ValueError:754            Raised if this is called with a ``dt`` which does not have this755            ``tzinfo`` attached.756 757        :return:758            Returns a :py:class:`datetime.datetime` object representing the759            wall time in ``self``'s time zone.760        """761        # These isinstance checks are in datetime.tzinfo, so we'll preserve762        # them, even if we don't care about duck typing.763        if not isinstance(dt, datetime.datetime):764            raise TypeError("fromutc() requires a datetime argument")765 766        if dt.tzinfo is not self:767            raise ValueError("dt.tzinfo is not self")768 769        # First treat UTC as wall time and get the transition we're in.770        idx = self._find_last_transition(dt, in_utc=True)771        tti = self._get_ttinfo(idx)772 773        dt_out = dt + datetime.timedelta(seconds=tti.offset)774 775        fold = self.is_ambiguous(dt_out, idx=idx)776 777        return enfold(dt_out, fold=int(fold))778 779    def is_ambiguous(self, dt, idx=None):780        """781        Whether or not the "wall time" of a given datetime is ambiguous in this782        zone.783 784        :param dt:785            A :py:class:`datetime.datetime`, naive or time zone aware.786 787 788        :return:789            Returns ``True`` if ambiguous, ``False`` otherwise.790 791        .. versionadded:: 2.6.0792        """793        if idx is None:794            idx = self._find_last_transition(dt)795 796        # Calculate the difference in offsets from current to previous797        timestamp = _datetime_to_timestamp(dt)798        tti = self._get_ttinfo(idx)799 800        if idx is None or idx <= 0:801            return False802 803        od = self._get_ttinfo(idx - 1).offset - tti.offset804        tt = self._trans_list[idx]          # Transition time805 806        return timestamp < tt + od807 808    def _resolve_ambiguous_time(self, dt):809        idx = self._find_last_transition(dt)810 811        # If we have no transitions, return the index812        _fold = self._fold(dt)813        if idx is None or idx == 0:814            return idx815 816        # If it's ambiguous and we're in a fold, shift to a different index.817        idx_offset = int(not _fold and self.is_ambiguous(dt, idx))818 819        return idx - idx_offset820 821    def utcoffset(self, dt):822        if dt is None:823            return None824 825        if not self._ttinfo_std:826            return ZERO827 828        return self._find_ttinfo(dt).delta829 830    def dst(self, dt):831        if dt is None:832            return None833 834        if not self._ttinfo_dst:835            return ZERO836 837        tti = self._find_ttinfo(dt)838 839        if not tti.isdst:840            return ZERO841 842        # The documentation says that utcoffset()-dst() must843        # be constant for every dt.844        return tti.dstoffset845 846    @tzname_in_python2847    def tzname(self, dt):848        if not self._ttinfo_std or dt is None:849            return None850        return self._find_ttinfo(dt).abbr851 852    def __eq__(self, other):853        if not isinstance(other, tzfile):854            return NotImplemented855        return (self._trans_list == other._trans_list and856                self._trans_idx == other._trans_idx and857                self._ttinfo_list == other._ttinfo_list)858 859    __hash__ = None860 861    def __ne__(self, other):862        return not (self == other)863 864    def __repr__(self):865        return "%s(%s)" % (self.__class__.__name__, repr(self._filename))866 867    def __reduce__(self):868        return self.__reduce_ex__(None)869 870    def __reduce_ex__(self, protocol):871        return (self.__class__, (None, self._filename), self.__dict__)872 873 874class tzrange(tzrangebase):875    """876    The ``tzrange`` object is a time zone specified by a set of offsets and877    abbreviations, equivalent to the way the ``TZ`` variable can be specified878    in POSIX-like systems, but using Python delta objects to specify DST879    start, end and offsets.880 881    :param stdabbr:882        The abbreviation for standard time (e.g. ``'EST'``).883 884    :param stdoffset:885        An integer or :class:`datetime.timedelta` object or equivalent886        specifying the base offset from UTC.887 888        If unspecified, +00:00 is used.889 890    :param dstabbr:891        The abbreviation for DST / "Summer" time (e.g. ``'EDT'``).892 893        If specified, with no other DST information, DST is assumed to occur894        and the default behavior or ``dstoffset``, ``start`` and ``end`` is895        used. If unspecified and no other DST information is specified, it896        is assumed that this zone has no DST.897 898        If this is unspecified and other DST information is *is* specified,899        DST occurs in the zone but the time zone abbreviation is left900        unchanged.901 902    :param dstoffset:903        A an integer or :class:`datetime.timedelta` object or equivalent904        specifying the UTC offset during DST. If unspecified and any other DST905        information is specified, it is assumed to be the STD offset +1 hour.906 907    :param start:908        A :class:`relativedelta.relativedelta` object or equivalent specifying909        the time and time of year that daylight savings time starts. To910        specify, for example, that DST starts at 2AM on the 2nd Sunday in911        March, pass:912 913            ``relativedelta(hours=2, month=3, day=1, weekday=SU(+2))``914 915        If unspecified and any other DST information is specified, the default916        value is 2 AM on the first Sunday in April.917 918    :param end:919        A :class:`relativedelta.relativedelta` object or equivalent920        representing the time and time of year that daylight savings time921        ends, with the same specification method as in ``start``. One note is922        that this should point to the first time in the *standard* zone, so if923        a transition occurs at 2AM in the DST zone and the clocks are set back924        1 hour to 1AM, set the ``hours`` parameter to +1.925 926 927    **Examples:**928 929    .. testsetup:: tzrange930 931        from dateutil.tz import tzrange, tzstr932 933    .. doctest:: tzrange934 935        >>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT")936        True937 938        >>> from dateutil.relativedelta import *939        >>> range1 = tzrange("EST", -18000, "EDT")940        >>> range2 = tzrange("EST", -18000, "EDT", -14400,941        ...                  relativedelta(hours=+2, month=4, day=1,942        ...                                weekday=SU(+1)),943        ...                  relativedelta(hours=+1, month=10, day=31,944        ...                                weekday=SU(-1)))945        >>> tzstr('EST5EDT') == range1 == range2946        True947 948    """949    def __init__(self, stdabbr, stdoffset=None,950                 dstabbr=None, dstoffset=None,951                 start=None, end=None):952 953        global relativedelta954        from dateutil import relativedelta955 956        self._std_abbr = stdabbr957        self._dst_abbr = dstabbr958 959        try:960            stdoffset = stdoffset.total_seconds()961        except (TypeError, AttributeError):962            pass963 964        try:965            dstoffset = dstoffset.total_seconds()966        except (TypeError, AttributeError):967            pass968 969        if stdoffset is not None:970            self._std_offset = datetime.timedelta(seconds=stdoffset)971        else:972            self._std_offset = ZERO973 974        if dstoffset is not None:975            self._dst_offset = datetime.timedelta(seconds=dstoffset)976        elif dstabbr and stdoffset is not None:977            self._dst_offset = self._std_offset + datetime.timedelta(hours=+1)978        else:979            self._dst_offset = ZERO980 981        if dstabbr and start is None:982            self._start_delta = relativedelta.relativedelta(983                hours=+2, month=4, day=1, weekday=relativedelta.SU(+1))984        else:985            self._start_delta = start986 987        if dstabbr and end is None:988            self._end_delta = relativedelta.relativedelta(989                hours=+1, month=10, day=31, weekday=relativedelta.SU(-1))990        else:991            self._end_delta = end992 993        self._dst_base_offset_ = self._dst_offset - self._std_offset994        self.hasdst = bool(self._start_delta)995 996    def transitions(self, year):997        """998        For a given year, get the DST on and off transition times, expressed999        always on the standard time side. For zones with no transitions, this1000        function returns ``None``.1001 1002        :param year:1003            The year whose transitions you would like to query.1004 1005        :return:1006            Returns a :class:`tuple` of :class:`datetime.datetime` objects,1007            ``(dston, dstoff)`` for zones with an annual DST transition, or1008            ``None`` for fixed offset zones.1009        """1010        if not self.hasdst:1011            return None1012 1013        base_year = datetime.datetime(year, 1, 1)1014 1015        start = base_year + self._start_delta1016        end = base_year + self._end_delta1017 1018        return (start, end)1019 1020    def __eq__(self, other):1021        if not isinstance(other, tzrange):1022            return NotImplemented1023 1024        return (self._std_abbr == other._std_abbr and1025                self._dst_abbr == other._dst_abbr and1026                self._std_offset == other._std_offset and1027                self._dst_offset == other._dst_offset and1028                self._start_delta == other._start_delta and1029                self._end_delta == other._end_delta)1030 1031    @property1032    def _dst_base_offset(self):1033        return self._dst_base_offset_1034 1035 1036@six.add_metaclass(_TzStrFactory)1037class tzstr(tzrange):1038    """1039    ``tzstr`` objects are time zone objects specified by a time-zone string as1040    it would be passed to a ``TZ`` variable on POSIX-style systems (see1041    the `GNU C Library: TZ Variable`_ for more details).1042 1043    There is one notable exception, which is that POSIX-style time zones use an1044    inverted offset format, so normally ``GMT+3`` would be parsed as an offset1045    3 hours *behind* GMT. The ``tzstr`` time zone object will parse this as an1046    offset 3 hours *ahead* of GMT. If you would like to maintain the POSIX1047    behavior, pass a ``True`` value to ``posix_offset``.1048 1049    The :class:`tzrange` object provides the same functionality, but is1050    specified using :class:`relativedelta.relativedelta` objects. rather than1051    strings.1052 1053    :param s:1054        A time zone string in ``TZ`` variable format. This can be a1055        :class:`bytes` (2.x: :class:`str`), :class:`str` (2.x:1056        :class:`unicode`) or a stream emitting unicode characters1057        (e.g. :class:`StringIO`).1058 1059    :param posix_offset:1060        Optional. If set to ``True``, interpret strings such as ``GMT+3`` or1061        ``UTC+3`` as being 3 hours *behind* UTC rather than ahead, per the1062        POSIX standard.1063 1064    .. caution::1065 1066        Prior to version 2.7.0, this function also supported time zones1067        in the format:1068 1069            * ``EST5EDT,4,0,6,7200,10,0,26,7200,3600``1070            * ``EST5EDT,4,1,0,7200,10,-1,0,7200,3600``1071 1072        This format is non-standard and has been deprecated; this function1073        will raise a :class:`DeprecatedTZFormatWarning` until1074        support is removed in a future version.1075 1076    .. _`GNU C Library: TZ Variable`:1077        https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html1078    """1079    def __init__(self, s, posix_offset=False):1080        global parser1081        from dateutil.parser import _parser as parser1082 1083        self._s = s1084 1085        res = parser._parsetz(s)1086        if res is None or res.any_unused_tokens:1087            raise ValueError("unknown string format")1088 1089        # Here we break the compatibility with the TZ variable handling.1090        # GMT-3 actually *means* the timezone -3.1091        if res.stdabbr in ("GMT", "UTC") and not posix_offset:1092            res.stdoffset *= -11093 1094        # We must initialize it first, since _delta() needs1095        # _std_offset and _dst_offset set. Use False in start/end1096        # to avoid building it two times.1097        tzrange.__init__(self, res.stdabbr, res.stdoffset,1098                         res.dstabbr, res.dstoffset,1099                         start=False, end=False)1100 1101        if not res.dstabbr:1102            self._start_delta = None1103            self._end_delta = None1104        else:1105            self._start_delta = self._delta(res.start)1106            if self._start_delta:1107                self._end_delta = self._delta(res.end, isend=1)1108 1109        self.hasdst = bool(self._start_delta)1110 1111    def _delta(self, x, isend=0):1112        from dateutil import relativedelta1113        kwargs = {}1114        if x.month is not None:1115            kwargs["month"] = x.month1116            if x.weekday is not None:1117                kwargs["weekday"] = relativedelta.weekday(x.weekday, x.week)1118                if x.week > 0:1119                    kwargs["day"] = 11120                else:1121                    kwargs["day"] = 311122            elif x.day:1123                kwargs["day"] = x.day1124        elif x.yday is not None:1125            kwargs["yearday"] = x.yday1126        elif x.jyday is not None:1127            kwargs["nlyearday"] = x.jyday1128        if not kwargs:1129            # Default is to start on first sunday of april, and end1130            # on last sunday of october.1131            if not isend:1132                kwargs["month"] = 41133                kwargs["day"] = 11134                kwargs["weekday"] = relativedelta.SU(+1)1135            else:1136                kwargs["month"] = 101137                kwargs["day"] = 311138                kwargs["weekday"] = relativedelta.SU(-1)1139        if x.time is not None:1140            kwargs["seconds"] = x.time1141        else:1142            # Default is 2AM.1143            kwargs["seconds"] = 72001144        if isend:1145            # Convert to standard time, to follow the documented way1146            # of working with the extra hour. See the documentation1147            # of the tzinfo class.1148            delta = self._dst_offset - self._std_offset1149            kwargs["seconds"] -= delta.seconds + delta.days * 864001150        return relativedelta.relativedelta(**kwargs)1151 1152    def __repr__(self):1153        return "%s(%s)" % (self.__class__.__name__, repr(self._s))1154 1155 1156class _tzicalvtzcomp(object):1157    def __init__(self, tzoffsetfrom, tzoffsetto, isdst,1158                 tzname=None, rrule=None):1159        self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom)1160        self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto)1161        self.tzoffsetdiff = self.tzoffsetto - self.tzoffsetfrom1162        self.isdst = isdst1163        self.tzname = tzname1164        self.rrule = rrule1165 1166 1167class _tzicalvtz(_tzinfo):1168    def __init__(self, tzid, comps=[]):1169        super(_tzicalvtz, self).__init__()1170 1171        self._tzid = tzid1172        self._comps = comps1173        self._cachedate = []1174        self._cachecomp = []1175        self._cache_lock = _thread.allocate_lock()1176 1177    def _find_comp(self, dt):1178        if len(self._comps) == 1:1179            return self._comps[0]1180 1181        dt = dt.replace(tzinfo=None)1182 1183        try:1184            with self._cache_lock:1185                return self._cachecomp[self._cachedate.index(1186                    (dt, self._fold(dt)))]1187        except ValueError:1188            pass1189 1190        lastcompdt = None1191        lastcomp = None1192 1193        for comp in self._comps:1194            compdt = self._find_compdt(comp, dt)1195 1196            if compdt and (not lastcompdt or lastcompdt < compdt):1197                lastcompdt = compdt1198                lastcomp = comp1199 1200        if not lastcomp:

Showing the first 1,200 of 1850 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai