| import re |
| import sys |
| |
| try: |
| from datetime import timezone |
| except ImportError: |
| from datetime import datetime |
| from datetime import timedelta |
| from datetime import tzinfo |
| |
| class timezone(tzinfo): |
| __slots__ = "_offset", "_name" |
| |
| # Sentinel value to disallow None |
| _Omitted = object() |
| |
| def __new__(cls, offset, name=_Omitted): |
| if not isinstance(offset, timedelta): |
| raise TypeError("offset must be a timedelta") |
| if name is cls._Omitted: |
| if not offset: |
| return cls.utc |
| name = None |
| elif not isinstance(name, str): |
| raise TypeError("name must be a string") |
| if not cls._minoffset <= offset <= cls._maxoffset: |
| raise ValueError( |
| "offset must be a timedelta " |
| "strictly between -timedelta(hours=24) and " |
| "timedelta(hours=24)." |
| ) |
| return cls._create(offset, name) |
| |
| @classmethod |
| def _create(cls, offset, name=None): |
| self = tzinfo.__new__(cls) |
| self._offset = offset |
| self._name = name |
| return self |
| |
| def __getinitargs__(self): |
| """pickle support""" |
| if self._name is None: |
| return (self._offset,) |
| return (self._offset, self._name) |
| |
| def __eq__(self, other): |
| if type(other) != timezone: |
| return False |
| return self._offset == other._offset |
| |
| def __hash__(self): |
| return hash(self._offset) |
| |
| def __repr__(self): |
| """Convert to formal string, for repr(). |
| |
| >>> tz = timezone.utc |
| >>> repr(tz) |
| 'datetime.timezone.utc' |
| >>> tz = timezone(timedelta(hours=-5), 'EST') |
| >>> repr(tz) |
| "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')" |
| """ |
| if self is self.utc: |
| return "datetime.timezone.utc" |
| if self._name is None: |
| return "%s.%s(%r)" % ( |
| self.__class__.__module__, |
| self.__class__.__name__, |
| self._offset, |
| ) |
| return "%s.%s(%r, %r)" % ( |
| self.__class__.__module__, |
| self.__class__.__name__, |
| self._offset, |
| self._name, |
| ) |
| |
| def __str__(self): |
| return self.tzname(None) |
| |
| def utcoffset(self, dt): |
| if isinstance(dt, datetime) or dt is None: |
| return self._offset |
| raise TypeError( |
| "utcoffset() argument must be a datetime instance" " or None" |
| ) |
| |
| def tzname(self, dt): |
| if isinstance(dt, datetime) or dt is None: |
| if self._name is None: |
| return self._name_from_offset(self._offset) |
| return self._name |
| raise TypeError("tzname() argument must be a datetime instance" " or None") |
| |
| def dst(self, dt): |
| if isinstance(dt, datetime) or dt is None: |
| return None |
| raise TypeError("dst() argument must be a datetime instance" " or None") |
| |
| def fromutc(self, dt): |
| if isinstance(dt, datetime): |
| if dt.tzinfo is not self: |
| raise ValueError("fromutc: dt.tzinfo " "is not self") |
| return dt + self._offset |
| raise TypeError("fromutc() argument must be a datetime instance" " or None") |
| |
| _maxoffset = timedelta(hours=23, minutes=59) |
| _minoffset = -_maxoffset |
| |
| @staticmethod |
| def _name_from_offset(delta): |
| if not delta: |
| return "UTC" |
| if delta < timedelta(0): |
| sign = "-" |
| delta = -delta |
| else: |
| sign = "+" |
| hours, rest = divmod(delta, timedelta(hours=1)) |
| minutes, rest = divmod(rest, timedelta(minutes=1)) |
| seconds = rest.seconds |
| microseconds = rest.microseconds |
| if microseconds: |
| return ("UTC{}{:02d}:{:02d}:{:02d}.{:06d}").format( |
| sign, hours, minutes, seconds, microseconds |
| ) |
| if seconds: |
| return "UTC{}{:02d}:{:02d}:{:02d}".format(sign, hours, minutes, seconds) |
| return "UTC{}{:02d}:{:02d}".format(sign, hours, minutes) |
| |
| timezone.utc = timezone._create(timedelta(0)) |
| timezone.min = timezone._create(timezone._minoffset) |
| timezone.max = timezone._create(timezone._maxoffset) |
| |
| |
| PY2 = sys.version_info[0] == 2 |
| PY36 = sys.version_info >= (3, 6) |
| PY38 = sys.version_info >= (3, 8) |
| |
| if PY2: |
| unicode = unicode |
| chr = unichr |
| long = long |
| else: |
| unicode = str |
| chr = chr |
| long = int |
| |
| |
| def decode(string, encodings=None): |
| if not PY2 and not isinstance(string, bytes): |
| return string |
| |
| if PY2 and isinstance(string, unicode): |
| return string |
| |
| encodings = encodings or ["utf-8", "latin1", "ascii"] |
| |
| for encoding in encodings: |
| try: |
| return string.decode(encoding) |
| except (UnicodeEncodeError, UnicodeDecodeError): |
| pass |
| |
| return string.decode(encodings[0], errors="ignore") |