codekingpro/portable-devtools
114k
1# Copyright 2017 The Kubernetes Authors.2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7# http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14 15import datetime16import math17import re18 19 20class TimezoneInfo(datetime.tzinfo):21 def __init__(self, h, m):22 self._name = "UTC"23 if h != 0 and m != 0:24 self._name += "%+03d:%2d" % (h, m)25 self._delta = datetime.timedelta(hours=h, minutes=math.copysign(m, h))26 27 def utcoffset(self, dt):28 return self._delta29 30 def tzname(self, dt):31 return self._name32 33 def dst(self, dt):34 return datetime.timedelta(0)35 36 37UTC = TimezoneInfo(0, 0)38 39# ref https://www.ietf.org/rfc/rfc3339.txt40_re_rfc3339 = re.compile(r"(\d\d\d\d)-(\d\d)-(\d\d)" # full-date41 r"[ Tt]" # Separator42 r"(\d\d):(\d\d):(\d\d)([.,]\d+)?" # partial-time43 r"([zZ ]|[-+]\d\d?:\d\d)?", # time-offset44 re.VERBOSE + re.IGNORECASE)45_re_timezone = re.compile(r"([-+])(\d\d?):?(\d\d)?")46 47MICROSEC_PER_SEC = 100000048 49 50def parse_rfc3339(s):51 if isinstance(s, datetime.datetime):52 if not s.tzinfo:53 return s.replace(tzinfo=UTC)54 return s55 56 m = _re_rfc3339.fullmatch(s.strip())57 if m is None:58 raise ValueError(59 f"Invalid RFC3339 datetime: {s!r} "60 "(expected YYYY-MM-DDTHH:MM:SS[.frac][Z|±HH:MM])"61 )62 63 groups = m.groups()64 dt = [0] * 765 for x in range(6):66 dt[x] = int(groups[x])67 68 us = 069 if groups[6] is not None:70 partial_sec = float(groups[6].replace(",", "."))71 us = int(MICROSEC_PER_SEC * partial_sec)72 73 tz = UTC74 if groups[7] is not None and groups[7] != 'Z' and groups[7] != 'z':75 tz_groups = _re_timezone.search(groups[7]).groups()76 hour = int(tz_groups[1])77 minute = 078 if tz_groups[0] == "-":79 hour *= -180 if tz_groups[2]:81 minute = int(tz_groups[2])82 tz = TimezoneInfo(hour, minute)83 84 try:85 return datetime.datetime(86 year=dt[0], month=dt[1], day=dt[2],87 hour=dt[3], minute=dt[4], second=dt[5],88 microsecond=us, tzinfo=tz)89 except ValueError as e:90 raise ValueError(91 f"Invalid date/time values in RFC3339 string {s!r}: {e}"92 ) from e93 94 95 96def format_rfc3339(date_time):97 if date_time.tzinfo is None:98 date_time = date_time.replace(tzinfo=UTC)99 date_time = date_time.astimezone(UTC)100 return date_time.strftime('%Y-%m-%dT%H:%M:%SZ')101 