Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(28)

Delta Between Two Patch Sets: Lib/datetime.py

Issue 15873: "datetime" cannot parse ISO 8601 dates and times
Left Patch Set: Created 4 years ago
Right Patch Set: Created 3 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | Lib/test/datetimetester.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 """Concrete date/time and related types. 1 """Concrete date/time and related types.
2 2
3 See http://www.iana.org/time-zones/repository/tz-link.html for 3 See http://www.iana.org/time-zones/repository/tz-link.html for
4 time zone and DST data sources. 4 time zone and DST data sources.
5 """ 5 """
6 6
7 import time as _time 7 import time as _time
8 import math as _math 8 import math as _math
9 import re 9 import re
10
11 DATE_RE = re.compile(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})$', re.ASC II)
12 TIME_RE = re.compile(r'(?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2})'
13 r'(?:(?P<microsecond>\.\d{1,7})\d*)?(?:(?P<tzinfo>Z|([+-]\d {2}:\d{2})))?$',
14 re.ASCII|re.IGNORECASE)
15 DATETIME_RE = re.compile(DATE_RE.pattern[:-1] + r'[T ]' + TIME_RE.pattern,
16 re.ASCII|re.IGNORECASE)
17 10
18 def _cmp(x, y): 11 def _cmp(x, y):
19 return 0 if x == y else 1 if x > y else -1 12 return 0 if x == y else 1 if x > y else -1
20 13
21 MINYEAR = 1 14 MINYEAR = 1
22 MAXYEAR = 9999 15 MAXYEAR = 9999
23 _MAXORDINAL = 3652059 # date.max.toordinal() 16 _MAXORDINAL = 3652059 # date.max.toordinal()
24 17
25 # Utility functions, adapted from Python's Demo/classes/Dates.py, which 18 # Utility functions, adapted from Python's Demo/classes/Dates.py, which
26 # also assumes the current Gregorian calendar indefinitely extended in 19 # also assumes the current Gregorian calendar indefinitely extended in
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 _MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun", 146 _MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
154 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 147 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
155 _DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] 148 _DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
156 149
157 150
158 def _build_struct_time(y, m, d, hh, mm, ss, dstflag): 151 def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
159 wday = (_ymd2ord(y, m, d) + 6) % 7 152 wday = (_ymd2ord(y, m, d) + 6) % 7
160 dnum = _days_before_month(y, m) + d 153 dnum = _days_before_month(y, m) + d
161 return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag)) 154 return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
162 155
163 def _format_time(hh, mm, ss, us): 156 def _format_time(hh, mm, ss, us, timespec='auto'):
164 # Skip trailing microseconds when us==0. 157 specs = {
165 result = "%02d:%02d:%02d" % (hh, mm, ss) 158 'hours': '{:02d}',
166 if us: 159 'minutes': '{:02d}:{:02d}',
167 result += ".%06d" % us 160 'seconds': '{:02d}:{:02d}:{:02d}',
168 return result 161 'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
162 'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
163 }
164
165 if timespec == 'auto':
166 # Skip trailing microseconds when us==0.
167 timespec = 'microseconds' if us else 'seconds'
168 elif timespec == 'milliseconds':
169 us //= 1000
170 try:
171 fmt = specs[timespec]
172 except KeyError:
173 raise ValueError('Unknown timespec value')
174 else:
175 return fmt.format(hh, mm, ss, us)
169 176
170 # Correctly substitute for %z and %Z escapes in strftime formats. 177 # Correctly substitute for %z and %Z escapes in strftime formats.
171 def _wrap_strftime(object, format, timetuple): 178 def _wrap_strftime(object, format, timetuple):
172 # Don't call utcoffset() or tzname() unless actually needed. 179 # Don't call utcoffset() or tzname() unless actually needed.
173 freplace = None # the string to use for %f 180 freplace = None # the string to use for %f
174 zreplace = None # the string to use for %z 181 zreplace = None # the string to use for %z
175 Zreplace = None # the string to use for %Z 182 Zreplace = None # the string to use for %Z
176 183
177 # Scan format for %z and %Z escapes, replacing as needed. 184 # Scan format for %z and %Z escapes, replacing as needed.
178 newformat = [] 185 newformat = []
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 # If offset is None, returns None. 244 # If offset is None, returns None.
238 # Else offset is checked for being in range, and a whole # of minutes. 245 # Else offset is checked for being in range, and a whole # of minutes.
239 # If it is, its integer value is returned. Else ValueError is raised. 246 # If it is, its integer value is returned. Else ValueError is raised.
240 def _check_utc_offset(name, offset): 247 def _check_utc_offset(name, offset):
241 assert name in ("utcoffset", "dst") 248 assert name in ("utcoffset", "dst")
242 if offset is None: 249 if offset is None:
243 return 250 return
244 if not isinstance(offset, timedelta): 251 if not isinstance(offset, timedelta):
245 raise TypeError("tzinfo.%s() must return None " 252 raise TypeError("tzinfo.%s() must return None "
246 "or timedelta, not '%s'" % (name, type(offset))) 253 "or timedelta, not '%s'" % (name, type(offset)))
247 if offset % timedelta(minutes=1) or offset.microseconds: 254 if offset.microseconds:
248 raise ValueError("tzinfo.%s() must return a whole number " 255 raise ValueError("tzinfo.%s() must return a whole number "
249 "of minutes, got %s" % (name, offset)) 256 "of seconds, got %s" % (name, offset))
250 if not -timedelta(1) < offset < timedelta(1): 257 if not -timedelta(1) < offset < timedelta(1):
251 raise ValueError("%s()=%s, must be must be strictly between " 258 raise ValueError("%s()=%s, must be strictly between "
252 "-timedelta(hours=24) and timedelta(hours=24)" % 259 "-timedelta(hours=24) and timedelta(hours=24)" %
253 (name, offset)) 260 (name, offset))
254 261
255 def _check_int_field(value): 262 def _check_int_field(value):
256 if isinstance(value, int): 263 if isinstance(value, int):
257 return value 264 return value
258 if not isinstance(value, float): 265 if not isinstance(value, float):
259 try: 266 try:
260 value = value.__int__() 267 value = value.__int__()
261 except AttributeError: 268 except AttributeError:
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 q, r = divmod(a, b) 323 q, r = divmod(a, b)
317 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd. 324 # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
318 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is 325 # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
319 # positive, 2 * r < b if b negative. 326 # positive, 2 * r < b if b negative.
320 r *= 2 327 r *= 2
321 greater_than_half = r > b if b > 0 else r < b 328 greater_than_half = r > b if b > 0 else r < b
322 if greater_than_half or r == b and q % 2 == 1: 329 if greater_than_half or r == b and q % 2 == 1:
323 q += 1 330 q += 1
324 331
325 return q 332 return q
333
334
335 def _parse_isotime(cls, isostring):
336 match = cls._isore.match(isostring)
337 if not match:
338 raise ValueError("invalid RFC 3339 %s string: %r"
339 % (cls.__name__, isostring))
340 kw = match.groupdict()
341 tzinfo = kw.pop('tzinfo', None)
342 if tzinfo == 'Z' or tzinfo == 'z':
343 tzinfo = timezone.utc
344 elif tzinfo is not None:
345 offset_hours, _, offset_mins = tzinfo[1:].partition(':')
346 offset = timedelta(hours=int(offset_hours), minutes=int(offset_mins))
347 if tzinfo[0] == '-':
348 offset = -offset
349 tzinfo = timezone(offset)
350 us = kw.pop('microsecond', None)
351 kw = {k: int(v) for k, v in kw.items()}
352 if us:
353 us = round(float(us), 6)
354 kw['microsecond'] = int(us * 1e6)
355 if tzinfo:
356 kw['tzinfo'] = tzinfo
357 return cls(**kw)
326 358
327 359
328 class timedelta: 360 class timedelta:
329 """Represent the difference between two datetime objects. 361 """Represent the difference between two datetime objects.
330 362
331 Supported operators: 363 Supported operators:
332 364
333 - add, subtract timedelta 365 - add, subtract timedelta
334 - unary plus, minus, abs 366 - unary plus, minus, abs
335 - compare to timedelta 367 - compare to timedelta
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 toordinal() 701 toordinal()
670 weekday() 702 weekday()
671 isoweekday(), isocalendar(), isoformat() 703 isoweekday(), isocalendar(), isoformat()
672 ctime() 704 ctime()
673 strftime() 705 strftime()
674 706
675 Properties (readonly): 707 Properties (readonly):
676 year, month, day 708 year, month, day
677 """ 709 """
678 __slots__ = '_year', '_month', '_day', '_hashcode' 710 __slots__ = '_year', '_month', '_day', '_hashcode'
711
712 _isore = re.compile(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})$', re. ASCII)
679 713
680 def __new__(cls, year, month=None, day=None): 714 def __new__(cls, year, month=None, day=None):
681 """Constructor. 715 """Constructor.
682 716
683 Arguments: 717 Arguments:
684 718
685 year, month, day (required, base 1) 719 year, month, day (required, base 1)
686 """ 720 """
687 if month is None and isinstance(year, bytes) and len(year) == 4 and \ 721 if month is None and isinstance(year, bytes) and len(year) == 4 and \
688 1 <= year[2] <= 12: 722 1 <= year[2] <= 12:
(...skipping 19 matching lines...) Expand all
708 return cls(y, m, d) 742 return cls(y, m, d)
709 743
710 @classmethod 744 @classmethod
711 def today(cls): 745 def today(cls):
712 "Construct a date from time.time()." 746 "Construct a date from time.time()."
713 t = _time.time() 747 t = _time.time()
714 return cls.fromtimestamp(t) 748 return cls.fromtimestamp(t)
715 749
716 @classmethod 750 @classmethod
717 def fromordinal(cls, n): 751 def fromordinal(cls, n):
718 """Contruct a date from a proleptic Gregorian ordinal. 752 """Construct a date from a proleptic Gregorian ordinal.
719 753
720 January 1 of year 1 is day 1. Only the year, month and day are 754 January 1 of year 1 is day 1. Only the year, month and day are
721 non-zero in the result. 755 non-zero in the result.
722 """ 756 """
723 y, m, d = _ord2ymd(n) 757 y, m, d = _ord2ymd(n)
724 return cls(y, m, d) 758 return cls(y, m, d)
725 759
726 @classmethod 760 @classmethod
727 def fromisoformat(cls, date_string): 761 def fromisoformat(cls, date_string):
728 """ Construct a date from an iso 8601 string 762 """Constructs a date from an RFC 3339 string, a strict subset of ISO 860 1
729 763
764 Raises ValueError in case of ill-formatted or invalid string.
730 """ 765 """
731 m = DATE_RE.match(date_string) 766 return _parse_isotime(cls, date_string)
732 if not m:
733 raise ValueError('invalid date string', date_string)
734 kw = m.groupdict()
735 kw = {k: int(v) for k, v in kw.items()}
736 return cls(**kw)
737 767
738 # Conversions to string 768 # Conversions to string
739 769
740 def __repr__(self): 770 def __repr__(self):
741 """Convert to formal string, for repr(). 771 """Convert to formal string, for repr().
742 772
743 >>> dt = datetime(2010, 1, 1) 773 >>> dt = datetime(2010, 1, 1)
744 >>> repr(dt) 774 >>> repr(dt)
745 'datetime.datetime(2010, 1, 1, 0, 0)' 775 'datetime.datetime(2010, 1, 1, 0, 0)'
746 776
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
929 week1monday = _isoweek1monday(year) 959 week1monday = _isoweek1monday(year)
930 week, day = divmod(today - week1monday, 7) 960 week, day = divmod(today - week1monday, 7)
931 elif week >= 52: 961 elif week >= 52:
932 if today >= _isoweek1monday(year+1): 962 if today >= _isoweek1monday(year+1):
933 year += 1 963 year += 1
934 week = 0 964 week = 0
935 return year, week+1, day+1 965 return year, week+1, day+1
936 966
937 # Pickle support. 967 # Pickle support.
938 968
939 def _getstate(self): 969 def _getstate(self, protocol=3):
940 yhi, ylo = divmod(self._year, 256) 970 yhi, ylo = divmod(self._year, 256)
941 return bytes([yhi, ylo, self._month, self._day]), 971 return bytes([yhi, ylo, self._month, self._day]),
942 972
943 def __setstate(self, string): 973 def __setstate(self, string):
944 yhi, ylo, self._month, self._day = string 974 yhi, ylo, self._month, self._day = string
945 self._year = yhi * 256 + ylo 975 self._year = yhi * 256 + ylo
946 976
947 def __reduce__(self): 977 def __reduce_ex__(self, protocol):
948 return (self.__class__, self._getstate()) 978 return (self.__class__, self._getstate(protocol))
949 979
950 _date_class = date # so functions w/ args named "date" can get at the class 980 _date_class = date # so functions w/ args named "date" can get at the class
951 981
952 date.min = date(1, 1, 1) 982 date.min = date(1, 1, 1)
953 date.max = date(9999, 12, 31) 983 date.max = date(9999, 12, 31)
954 date.resolution = timedelta(days=1) 984 date.resolution = timedelta(days=1)
985
955 986
956 class tzinfo: 987 class tzinfo:
957 """Abstract base class for time zone info classes. 988 """Abstract base class for time zone info classes.
958 989
959 Subclasses must override the name(), utcoffset() and dst() methods. 990 Subclasses must override the name(), utcoffset() and dst() methods.
960 """ 991 """
961 __slots__ = () 992 __slots__ = ()
962 993
963 def tzname(self, dt): 994 def tzname(self, dt):
964 "datetime -> string name of time zone." 995 "datetime -> string name of time zone."
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1016 state = getstate() 1047 state = getstate()
1017 else: 1048 else:
1018 state = getattr(self, "__dict__", None) or None 1049 state = getattr(self, "__dict__", None) or None
1019 if state is None: 1050 if state is None:
1020 return (self.__class__, args) 1051 return (self.__class__, args)
1021 else: 1052 else:
1022 return (self.__class__, args, state) 1053 return (self.__class__, args, state)
1023 1054
1024 _tzinfo_class = tzinfo 1055 _tzinfo_class = tzinfo
1025 1056
1057
1026 class time: 1058 class time:
1027 """Time with time zone. 1059 """Time with time zone.
1028 1060
1029 Constructors: 1061 Constructors:
1030 1062
1031 __new__() 1063 __new__()
1032 1064
1033 Operators: 1065 Operators:
1034 1066
1035 __repr__, __str__ 1067 __repr__, __str__
1036 __eq__, __le__, __lt__, __ge__, __gt__, __hash__ 1068 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
1037 1069
1038 Methods: 1070 Methods:
1039 1071
1040 strftime() 1072 strftime()
1041 isoformat() 1073 isoformat()
1042 utcoffset() 1074 utcoffset()
1043 tzname() 1075 tzname()
1044 dst() 1076 dst()
1045 1077
1046 Properties (readonly): 1078 Properties (readonly):
1047 hour, minute, second, microsecond, tzinfo 1079 hour, minute, second, microsecond, tzinfo, fold
1048 """ 1080 """
1049 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hash code' 1081 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hash code', '_fold'
1050 1082
1051 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None): 1083 _isore = re.compile(r'(?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2})'
1084 r'(?P<microsecond>\.\d+)?(?P<tzinfo>Z|[+-]\d{2}:\d{2})?$ ',
1085 re.ASCII|re.IGNORECASE)
1086
1087
1088 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
1052 """Constructor. 1089 """Constructor.
1053 1090
1054 Arguments: 1091 Arguments:
1055 1092
1056 hour, minute (required) 1093 hour, minute (required)
1057 second, microsecond (default to zero) 1094 second, microsecond (default to zero)
1058 tzinfo (default to None) 1095 tzinfo (default to None)
1096 fold (keyword only, default to True)
1059 """ 1097 """
1060 if isinstance(hour, bytes) and len(hour) == 6 and hour[0] < 24: 1098 if isinstance(hour, bytes) and len(hour) == 6 and hour[0]&0x7F < 24:
1061 # Pickle support 1099 # Pickle support
1062 self = object.__new__(cls) 1100 self = object.__new__(cls)
1063 self.__setstate(hour, minute or None) 1101 self.__setstate(hour, minute or None)
1064 self._hashcode = -1 1102 self._hashcode = -1
1065 return self 1103 return self
1066 hour, minute, second, microsecond = _check_time_fields( 1104 hour, minute, second, microsecond = _check_time_fields(
1067 hour, minute, second, microsecond) 1105 hour, minute, second, microsecond)
1068 _check_tzinfo_arg(tzinfo) 1106 _check_tzinfo_arg(tzinfo)
1069 self = object.__new__(cls) 1107 self = object.__new__(cls)
1070 self._hour = hour 1108 self._hour = hour
1071 self._minute = minute 1109 self._minute = minute
1072 self._second = second 1110 self._second = second
1073 self._microsecond = microsecond 1111 self._microsecond = microsecond
1074 self._tzinfo = tzinfo 1112 self._tzinfo = tzinfo
1075 self._hashcode = -1 1113 self._hashcode = -1
1114 self._fold = fold
1076 return self 1115 return self
1077
1078 @staticmethod
1079 def _parse_isotime(reg, isostring, objekt):
1080 match = reg.match(isostring)
1081 if not match:
1082 raise ValueError('invalid iso8601 %s string: "%s"' % (objekt, isostr ing))
1083 kw = match.groupdict()
1084 tzinfo = kw.pop('tzinfo', None)
1085 if tzinfo == 'Z' or tzinfo == 'z':
1086 tzinfo = timezone.utc
1087 elif tzinfo is not None:
1088 offset_hours, offset_mins = tzinfo[1:].split(':')
1089 offset = timedelta(hours=int(offset_hours), minutes=int(offset_mins) )
1090 if tzinfo[0] == '-':
1091 offset = -offset
1092 tzinfo = timezone(offset)
1093 us = kw.pop('microsecond', None)
1094 kw = {k: int(v) for k, v in kw.items() if v is not None}
1095 if us:
1096 us = round(float(us), 6)
1097 kw['microsecond'] = int(us * 1e6)
1098 kw['tzinfo'] = tzinfo
1099 return kw
1100 1116
1101 @classmethod 1117 @classmethod
1102 def fromisoformat(cls, time_string): 1118 def fromisoformat(cls, time_string):
1103 """ Constructs a time object from an iso 8601 string 1119 """Constructs a time from an RFC 3339 string, a strict subset of ISO 860 1
1120
1121 Microseconds are rounded to 6 digits.
1122 Raises ValueError in case of ill-formatted or invalid string.
1104 """ 1123 """
1105 kw = cls._parse_isotime(TIME_RE, time_string, __name__) 1124 return _parse_isotime(cls, time_string)
1106 return cls(**kw)
1107
1108 1125
1109 # Read-only field accessors 1126 # Read-only field accessors
1110 @property 1127 @property
1111 def hour(self): 1128 def hour(self):
1112 """hour (0-23)""" 1129 """hour (0-23)"""
1113 return self._hour 1130 return self._hour
1114 1131
1115 @property 1132 @property
1116 def minute(self): 1133 def minute(self):
1117 """minute (0-59)""" 1134 """minute (0-59)"""
1118 return self._minute 1135 return self._minute
1119 1136
1120 @property 1137 @property
1121 def second(self): 1138 def second(self):
1122 """second (0-59)""" 1139 """second (0-59)"""
1123 return self._second 1140 return self._second
1124 1141
1125 @property 1142 @property
1126 def microsecond(self): 1143 def microsecond(self):
1127 """microsecond (0-999999)""" 1144 """microsecond (0-999999)"""
1128 return self._microsecond 1145 return self._microsecond
1129 1146
1130 @property 1147 @property
1131 def tzinfo(self): 1148 def tzinfo(self):
1132 """timezone info object""" 1149 """timezone info object"""
1133 return self._tzinfo 1150 return self._tzinfo
1151
1152 @property
1153 def fold(self):
1154 return self._fold
1134 1155
1135 # Standard conversions, __hash__ (and helpers) 1156 # Standard conversions, __hash__ (and helpers)
1136 1157
1137 # Comparisons of time objects with other. 1158 # Comparisons of time objects with other.
1138 1159
1139 def __eq__(self, other): 1160 def __eq__(self, other):
1140 if isinstance(other, time): 1161 if isinstance(other, time):
1141 return self._cmp(other, allow_mixed=True) == 0 1162 return self._cmp(other, allow_mixed=True) == 0
1142 else: 1163 else:
1143 return False 1164 return False
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1190 else: 1211 else:
1191 raise TypeError("cannot compare naive and aware times") 1212 raise TypeError("cannot compare naive and aware times")
1192 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1) 1213 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1193 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1) 1214 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1194 return _cmp((myhhmm, self._second, self._microsecond), 1215 return _cmp((myhhmm, self._second, self._microsecond),
1195 (othhmm, other._second, other._microsecond)) 1216 (othhmm, other._second, other._microsecond))
1196 1217
1197 def __hash__(self): 1218 def __hash__(self):
1198 """Hash.""" 1219 """Hash."""
1199 if self._hashcode == -1: 1220 if self._hashcode == -1:
1200 tzoff = self.utcoffset() 1221 if self.fold:
1222 t = self.replace(fold=0)
1223 else:
1224 t = self
1225 tzoff = t.utcoffset()
1201 if not tzoff: # zero or None 1226 if not tzoff: # zero or None
1202 self._hashcode = hash(self._getstate()[0]) 1227 self._hashcode = hash(t._getstate()[0])
1203 else: 1228 else:
1204 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff, 1229 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1205 timedelta(hours=1)) 1230 timedelta(hours=1))
1206 assert not m % timedelta(minutes=1), "whole minute" 1231 assert not m % timedelta(minutes=1), "whole minute"
1207 m //= timedelta(minutes=1) 1232 m //= timedelta(minutes=1)
1208 if 0 <= h < 24: 1233 if 0 <= h < 24:
1209 self._hashcode = hash(time(h, m, self.second, self.microseco nd)) 1234 self._hashcode = hash(time(h, m, self.second, self.microseco nd))
1210 else: 1235 else:
1211 self._hashcode = hash((h, m, self.second, self.microsecond)) 1236 self._hashcode = hash((h, m, self.second, self.microsecond))
1212 return self._hashcode 1237 return self._hashcode
1213 1238
1214 # Conversion to string 1239 # Conversion to string
1215 1240
1216 def _tzstr(self, sep=":"): 1241 def _tzstr(self, sep=":"):
1217 """Return formatted timezone offset (+xx:xx) or None.""" 1242 """Return formatted timezone offset (+xx:xx) or None."""
1218 off = self.utcoffset() 1243 off = self.utcoffset()
1219 if off is not None: 1244 if off is not None:
1220 if off.days < 0: 1245 if off.days < 0:
1221 sign = "-" 1246 sign = "-"
1222 off = -off 1247 off = -off
1223 else: 1248 else:
1224 sign = "+" 1249 sign = "+"
1225 hh, mm = divmod(off, timedelta(hours=1)) 1250 hh, mm = divmod(off, timedelta(hours=1))
1226 assert not mm % timedelta(minutes=1), "whole minute" 1251 mm, ss = divmod(mm, timedelta(minutes=1))
1227 mm //= timedelta(minutes=1)
1228 assert 0 <= hh < 24 1252 assert 0 <= hh < 24
1229 off = "%s%02d%s%02d" % (sign, hh, sep, mm) 1253 off = "%s%02d%s%02d" % (sign, hh, sep, mm)
1254 if ss:
1255 off += ':%02d' % ss.seconds
1230 return off 1256 return off
1231 1257
1232 def __repr__(self): 1258 def __repr__(self):
1233 """Convert to formal string, for repr().""" 1259 """Convert to formal string, for repr()."""
1234 if self._microsecond != 0: 1260 if self._microsecond != 0:
1235 s = ", %d, %d" % (self._second, self._microsecond) 1261 s = ", %d, %d" % (self._second, self._microsecond)
1236 elif self._second != 0: 1262 elif self._second != 0:
1237 s = ", %d" % self._second 1263 s = ", %d" % self._second
1238 else: 1264 else:
1239 s = "" 1265 s = ""
1240 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__, 1266 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1241 self.__class__.__qualname__, 1267 self.__class__.__qualname__,
1242 self._hour, self._minute, s) 1268 self._hour, self._minute, s)
1243 if self._tzinfo is not None: 1269 if self._tzinfo is not None:
1244 assert s[-1:] == ")" 1270 assert s[-1:] == ")"
1245 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")" 1271 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1272 if self._fold:
1273 assert s[-1:] == ")"
1274 s = s[:-1] + ", fold=1)"
1246 return s 1275 return s
1247 1276
1248 def isoformat(self): 1277 def isoformat(self, timespec='auto'):
1249 """Return the time formatted according to ISO. 1278 """Return the time formatted according to ISO.
1250 1279
1251 This is 'HH:MM:SS.mmmmmm+zz:zz', or 'HH:MM:SS+zz:zz' if 1280 The full format is 'HH:MM:SS.mmmmmm+zz:zz'. By default, the fractional
1252 self.microsecond == 0. 1281 part is omitted if self.microsecond == 0.
1282
1283 The optional argument timespec specifies the number of additional
1284 terms of the time to include.
1253 """ 1285 """
1254 s = _format_time(self._hour, self._minute, self._second, 1286 s = _format_time(self._hour, self._minute, self._second,
1255 self._microsecond) 1287 self._microsecond, timespec)
1256 tz = self._tzstr() 1288 tz = self._tzstr()
1257 if tz: 1289 if tz:
1258 s += tz 1290 s += tz
1259 return s 1291 return s
1260 1292
1261 __str__ = isoformat 1293 __str__ = isoformat
1262 1294
1263 def strftime(self, fmt): 1295 def strftime(self, fmt):
1264 """Format using strftime(). The date part of the timestamp passed 1296 """Format using strftime(). The date part of the timestamp passed
1265 to underlying strftime should not be used. 1297 to underlying strftime should not be used.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1311 need to consult dst() unless you're interested in displaying the DST 1343 need to consult dst() unless you're interested in displaying the DST
1312 info. 1344 info.
1313 """ 1345 """
1314 if self._tzinfo is None: 1346 if self._tzinfo is None:
1315 return None 1347 return None
1316 offset = self._tzinfo.dst(None) 1348 offset = self._tzinfo.dst(None)
1317 _check_utc_offset("dst", offset) 1349 _check_utc_offset("dst", offset)
1318 return offset 1350 return offset
1319 1351
1320 def replace(self, hour=None, minute=None, second=None, microsecond=None, 1352 def replace(self, hour=None, minute=None, second=None, microsecond=None,
1321 tzinfo=True): 1353 tzinfo=True, *, fold=None):
1322 """Return a new time with new values for the specified fields.""" 1354 """Return a new time with new values for the specified fields."""
1323 if hour is None: 1355 if hour is None:
1324 hour = self.hour 1356 hour = self.hour
1325 if minute is None: 1357 if minute is None:
1326 minute = self.minute 1358 minute = self.minute
1327 if second is None: 1359 if second is None:
1328 second = self.second 1360 second = self.second
1329 if microsecond is None: 1361 if microsecond is None:
1330 microsecond = self.microsecond 1362 microsecond = self.microsecond
1331 if tzinfo is True: 1363 if tzinfo is True:
1332 tzinfo = self.tzinfo 1364 tzinfo = self.tzinfo
1333 return time(hour, minute, second, microsecond, tzinfo) 1365 if fold is None:
1366 fold = self._fold
1367 return time(hour, minute, second, microsecond, tzinfo, fold=fold)
1334 1368
1335 # Pickle support. 1369 # Pickle support.
1336 1370
1337 def _getstate(self): 1371 def _getstate(self, protocol=3):
1338 us2, us3 = divmod(self._microsecond, 256) 1372 us2, us3 = divmod(self._microsecond, 256)
1339 us1, us2 = divmod(us2, 256) 1373 us1, us2 = divmod(us2, 256)
1340 basestate = bytes([self._hour, self._minute, self._second, 1374 h = self._hour
1375 if self._fold and protocol > 3:
1376 h += 128
1377 basestate = bytes([h, self._minute, self._second,
1341 us1, us2, us3]) 1378 us1, us2, us3])
1342 if self._tzinfo is None: 1379 if self._tzinfo is None:
1343 return (basestate,) 1380 return (basestate,)
1344 else: 1381 else:
1345 return (basestate, self._tzinfo) 1382 return (basestate, self._tzinfo)
1346 1383
1347 def __setstate(self, string, tzinfo): 1384 def __setstate(self, string, tzinfo):
1348 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class): 1385 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1349 raise TypeError("bad tzinfo state arg") 1386 raise TypeError("bad tzinfo state arg")
1350 self._hour, self._minute, self._second, us1, us2, us3 = string 1387 h, self._minute, self._second, us1, us2, us3 = string
1388 if h > 127:
1389 self._fold = 1
1390 self._hour = h - 128
1391 else:
1392 self._fold = 0
1393 self._hour = h
1351 self._microsecond = (((us1 << 8) | us2) << 8) | us3 1394 self._microsecond = (((us1 << 8) | us2) << 8) | us3
1352 self._tzinfo = tzinfo 1395 self._tzinfo = tzinfo
1353 1396
1354 def __reduce__(self): 1397 def __reduce_ex__(self, protocol):
1355 return (time, self._getstate()) 1398 return (time, self._getstate(protocol))
1356 1399
1357 _time_class = time # so functions w/ args named "time" can get at the class 1400 _time_class = time # so functions w/ args named "time" can get at the class
1358 1401
1359 time.min = time(0, 0, 0) 1402 time.min = time(0, 0, 0)
1360 time.max = time(23, 59, 59, 999999) 1403 time.max = time(23, 59, 59, 999999)
1361 time.resolution = timedelta(microseconds=1) 1404 time.resolution = timedelta(microseconds=1)
1362 1405
1363 class datetime(date): 1406 class datetime(date):
1364 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo] ]]]]) 1407 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo] ]]]])
1365 1408
1366 The year, month and day arguments are required. tzinfo may be None, or an 1409 The year, month and day arguments are required. tzinfo may be None, or an
1367 instance of a tzinfo subclass. The remaining arguments may be ints. 1410 instance of a tzinfo subclass. The remaining arguments may be ints.
1368 """ 1411 """
1369 __slots__ = date.__slots__ + time.__slots__ 1412 __slots__ = date.__slots__ + time.__slots__
1370 1413
1414 _isore = re.compile(date._isore.pattern[:-1] + r'[T ]' +
1415 time._isore.pattern, re.ASCII|re.IGNORECASE)
1416
1371 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0, 1417 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
1372 microsecond=0, tzinfo=None): 1418 microsecond=0, tzinfo=None, *, fold=0):
1373 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2] <= 12: 1419 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12:
1374 # Pickle support 1420 # Pickle support
1375 self = object.__new__(cls) 1421 self = object.__new__(cls)
1376 self.__setstate(year, month) 1422 self.__setstate(year, month)
1377 self._hashcode = -1 1423 self._hashcode = -1
1378 return self 1424 return self
1379 year, month, day = _check_date_fields(year, month, day) 1425 year, month, day = _check_date_fields(year, month, day)
1380 hour, minute, second, microsecond = _check_time_fields( 1426 hour, minute, second, microsecond = _check_time_fields(
1381 hour, minute, second, microsecond) 1427 hour, minute, second, microsecond)
1382 _check_tzinfo_arg(tzinfo) 1428 _check_tzinfo_arg(tzinfo)
1383 self = object.__new__(cls) 1429 self = object.__new__(cls)
1384 self._year = year 1430 self._year = year
1385 self._month = month 1431 self._month = month
1386 self._day = day 1432 self._day = day
1387 self._hour = hour 1433 self._hour = hour
1388 self._minute = minute 1434 self._minute = minute
1389 self._second = second 1435 self._second = second
1390 self._microsecond = microsecond 1436 self._microsecond = microsecond
1391 self._tzinfo = tzinfo 1437 self._tzinfo = tzinfo
1392 self._hashcode = -1 1438 self._hashcode = -1
1439 self._fold = fold
1393 return self 1440 return self
1394 1441
1395 # Read-only field accessors 1442 # Read-only field accessors
1396 @property 1443 @property
1397 def hour(self): 1444 def hour(self):
1398 """hour (0-23)""" 1445 """hour (0-23)"""
1399 return self._hour 1446 return self._hour
1400 1447
1401 @property 1448 @property
1402 def minute(self): 1449 def minute(self):
1403 """minute (0-59)""" 1450 """minute (0-59)"""
1404 return self._minute 1451 return self._minute
1405 1452
1406 @property 1453 @property
1407 def second(self): 1454 def second(self):
1408 """second (0-59)""" 1455 """second (0-59)"""
1409 return self._second 1456 return self._second
1410 1457
1411 @property 1458 @property
1412 def microsecond(self): 1459 def microsecond(self):
1413 """microsecond (0-999999)""" 1460 """microsecond (0-999999)"""
1414 return self._microsecond 1461 return self._microsecond
1415 1462
1416 @property 1463 @property
1417 def tzinfo(self): 1464 def tzinfo(self):
1418 """timezone info object""" 1465 """timezone info object"""
1419 return self._tzinfo 1466 return self._tzinfo
1467
1468 @property
1469 def fold(self):
1470 return self._fold
1420 1471
1421 @classmethod 1472 @classmethod
1422 def _fromtimestamp(cls, t, utc, tz): 1473 def _fromtimestamp(cls, t, utc, tz):
1423 """Construct a datetime from a POSIX timestamp (like time.time()). 1474 """Construct a datetime from a POSIX timestamp (like time.time()).
1424 1475
1425 A timezone info object may be passed in as well. 1476 A timezone info object may be passed in as well.
1426 """ 1477 """
1427 frac, t = _math.modf(t) 1478 frac, t = _math.modf(t)
1428 us = round(frac * 1e6) 1479 us = round(frac * 1e6)
1429 if us >= 1000000: 1480 if us >= 1000000:
1430 t += 1 1481 t += 1
1431 us -= 1000000 1482 us -= 1000000
1432 elif us < 0: 1483 elif us < 0:
1433 t -= 1 1484 t -= 1
1434 us += 1000000 1485 us += 1000000
1435 1486
1436 converter = _time.gmtime if utc else _time.localtime 1487 converter = _time.gmtime if utc else _time.localtime
1437 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) 1488 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1438 ss = min(ss, 59) # clamp out leap seconds if the platform has them 1489 ss = min(ss, 59) # clamp out leap seconds if the platform has them
1439 return cls(y, m, d, hh, mm, ss, us, tz) 1490 result = cls(y, m, d, hh, mm, ss, us, tz)
1491 if tz is None:
1492 # As of version 2015f max fold in IANA database is
1493 # 23 hours at 1969-09-30 13:00:00 in Kwajalein.
1494 # Let's probe 24 hours in the past to detect a transition:
1495 max_fold_seconds = 24 * 3600
1496 y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1497 probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1498 trans = result - probe1 - timedelta(0, max_fold_seconds)
1499 if trans.days < 0:
1500 y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6 ]
1501 probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1502 if probe2 == result:
1503 result._fold = 1
1504 else:
1505 result = tz.fromutc(result)
1506 return result
1440 1507
1441 @classmethod 1508 @classmethod
1442 def fromtimestamp(cls, t, tz=None): 1509 def fromtimestamp(cls, t, tz=None):
1443 """Construct a datetime from a POSIX timestamp (like time.time()). 1510 """Construct a datetime from a POSIX timestamp (like time.time()).
1444 1511
1445 A timezone info object may be passed in as well. 1512 A timezone info object may be passed in as well.
1446 """ 1513 """
1447 _check_tzinfo_arg(tz) 1514 _check_tzinfo_arg(tz)
1448 1515
1449 result = cls._fromtimestamp(t, tz is not None, tz) 1516 return cls._fromtimestamp(t, tz is not None, tz)
1450 if tz is not None:
1451 result = tz.fromutc(result)
1452 return result
1453 1517
1454 @classmethod 1518 @classmethod
1455 def utcfromtimestamp(cls, t): 1519 def utcfromtimestamp(cls, t):
1456 """Construct a naive UTC datetime from a POSIX timestamp.""" 1520 """Construct a naive UTC datetime from a POSIX timestamp."""
1457 return cls._fromtimestamp(t, True, None) 1521 return cls._fromtimestamp(t, True, None)
1458 1522
1459 @classmethod 1523 @classmethod
1460 def now(cls, tz=None): 1524 def now(cls, tz=None):
1461 "Construct a datetime from time.time() and optional time zone info." 1525 "Construct a datetime from time.time() and optional time zone info."
1462 t = _time.time() 1526 t = _time.time()
1463 return cls.fromtimestamp(t, tz) 1527 return cls.fromtimestamp(t, tz)
1464 1528
1465 @classmethod 1529 @classmethod
1466 def utcnow(cls): 1530 def utcnow(cls):
1467 "Construct a UTC datetime from time.time()." 1531 "Construct a UTC datetime from time.time()."
1468 t = _time.time() 1532 t = _time.time()
1469 return cls.utcfromtimestamp(t) 1533 return cls.utcfromtimestamp(t)
1470 1534
1471 @classmethod 1535 @classmethod
1472 def combine(cls, date, time): 1536 def combine(cls, date, time, tzinfo=True):
1473 "Construct a datetime from a given date and a given time." 1537 "Construct a datetime from a given date and a given time."
1474 if not isinstance(date, _date_class): 1538 if not isinstance(date, _date_class):
1475 raise TypeError("date argument must be a date instance") 1539 raise TypeError("date argument must be a date instance")
1476 if not isinstance(time, _time_class): 1540 if not isinstance(time, _time_class):
1477 raise TypeError("time argument must be a time instance") 1541 raise TypeError("time argument must be a time instance")
1542 if tzinfo is True:
1543 tzinfo = time.tzinfo
1478 return cls(date.year, date.month, date.day, 1544 return cls(date.year, date.month, date.day,
1479 time.hour, time.minute, time.second, time.microsecond, 1545 time.hour, time.minute, time.second, time.microsecond,
1480 time.tzinfo) 1546 tzinfo, fold=time.fold)
1481
1482 @classmethod
1483 def fromisoformat(cls, datetime_string):
1484 kw = time._parse_isotime(DATETIME_RE, datetime_string, __name__)
1485 return cls(**kw)
1486 1547
1487 def timetuple(self): 1548 def timetuple(self):
1488 "Return local time tuple compatible with time.localtime()." 1549 "Return local time tuple compatible with time.localtime()."
1489 dst = self.dst() 1550 dst = self.dst()
1490 if dst is None: 1551 if dst is None:
1491 dst = -1 1552 dst = -1
1492 elif dst: 1553 elif dst:
1493 dst = 1 1554 dst = 1
1494 else: 1555 else:
1495 dst = 0 1556 dst = 0
1496 return _build_struct_time(self.year, self.month, self.day, 1557 return _build_struct_time(self.year, self.month, self.day,
1497 self.hour, self.minute, self.second, 1558 self.hour, self.minute, self.second,
1498 dst) 1559 dst)
1499 1560
1561 def _mktime(self):
1562 """Return integer POSIX timestamp."""
1563 epoch = datetime(1970, 1, 1)
1564 max_fold_seconds = 24 * 3600
1565 t = (self - epoch) // timedelta(0, 1)
1566 def local(u):
1567 y, m, d, hh, mm, ss = _time.localtime(u)[:6]
1568 return (datetime(y, m, d, hh, mm, ss) - epoch) // timedelta(0, 1)
1569
1570 # Our goal is to solve t = local(u) for u.
1571 a = local(t) - t
1572 u1 = t - a
1573 t1 = local(u1)
1574 if t1 == t:
1575 # We found one solution, but it may not be the one we need.
1576 # Look for an earlier solution (if `fold` is 0), or a
1577 # later one (if `fold` is 1).
1578 u2 = u1 + (-max_fold_seconds, max_fold_seconds)[self.fold]
1579 b = local(u2) - u2
1580 if a == b:
1581 return u1
1582 else:
1583 b = t1 - u1
1584 assert a != b
1585 u2 = t - b
1586 t2 = local(u2)
1587 if t2 == t:
1588 return u2
1589 if t1 == t:
1590 return u1
1591 # We have found both offsets a and b, but neither t - a nor t - b is
1592 # a solution. This means t is in the gap.
1593 return (max, min)[self.fold](u1, u2)
1594
1595
1500 def timestamp(self): 1596 def timestamp(self):
1501 "Return POSIX timestamp as float" 1597 "Return POSIX timestamp as float"
1502 if self._tzinfo is None: 1598 if self._tzinfo is None:
1503 return _time.mktime((self.year, self.month, self.day, 1599 s = self._mktime()
1504 self.hour, self.minute, self.second, 1600 return s + self.microsecond / 1e6
1505 -1, -1, -1)) + self.microsecond / 1e6
1506 else: 1601 else:
1507 return (self - _EPOCH).total_seconds() 1602 return (self - _EPOCH).total_seconds()
1508 1603
1509 def utctimetuple(self): 1604 def utctimetuple(self):
1510 "Return UTC time tuple compatible with time.gmtime()." 1605 "Return UTC time tuple compatible with time.gmtime()."
1511 offset = self.utcoffset() 1606 offset = self.utcoffset()
1512 if offset: 1607 if offset:
1513 self -= offset 1608 self -= offset
1514 y, m, d = self.year, self.month, self.day 1609 y, m, d = self.year, self.month, self.day
1515 hh, mm, ss = self.hour, self.minute, self.second 1610 hh, mm, ss = self.hour, self.minute, self.second
1516 return _build_struct_time(y, m, d, hh, mm, ss, 0) 1611 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1517 1612
1518 def date(self): 1613 def date(self):
1519 "Return the date part." 1614 "Return the date part."
1520 return date(self._year, self._month, self._day) 1615 return date(self._year, self._month, self._day)
1521 1616
1522 def time(self): 1617 def time(self):
1523 "Return the time part, with tzinfo None." 1618 "Return the time part, with tzinfo None."
1524 return time(self.hour, self.minute, self.second, self.microsecond) 1619 return time(self.hour, self.minute, self.second, self.microsecond, fold= self.fold)
1525 1620
1526 def timetz(self): 1621 def timetz(self):
1527 "Return the time part, with same tzinfo." 1622 "Return the time part, with same tzinfo."
1528 return time(self.hour, self.minute, self.second, self.microsecond, 1623 return time(self.hour, self.minute, self.second, self.microsecond,
1529 self._tzinfo) 1624 self._tzinfo, fold=self.fold)
1530 1625
1531 def replace(self, year=None, month=None, day=None, hour=None, 1626 def replace(self, year=None, month=None, day=None, hour=None,
1532 minute=None, second=None, microsecond=None, tzinfo=True): 1627 minute=None, second=None, microsecond=None, tzinfo=True,
1628 *, fold=None):
1533 """Return a new datetime with new values for the specified fields.""" 1629 """Return a new datetime with new values for the specified fields."""
1534 if year is None: 1630 if year is None:
1535 year = self.year 1631 year = self.year
1536 if month is None: 1632 if month is None:
1537 month = self.month 1633 month = self.month
1538 if day is None: 1634 if day is None:
1539 day = self.day 1635 day = self.day
1540 if hour is None: 1636 if hour is None:
1541 hour = self.hour 1637 hour = self.hour
1542 if minute is None: 1638 if minute is None:
1543 minute = self.minute 1639 minute = self.minute
1544 if second is None: 1640 if second is None:
1545 second = self.second 1641 second = self.second
1546 if microsecond is None: 1642 if microsecond is None:
1547 microsecond = self.microsecond 1643 microsecond = self.microsecond
1548 if tzinfo is True: 1644 if tzinfo is True:
1549 tzinfo = self.tzinfo 1645 tzinfo = self.tzinfo
1550 return datetime(year, month, day, hour, minute, second, microsecond, 1646 if fold is None:
1551 tzinfo) 1647 fold = self.fold
1648 return datetime(year, month, day, hour, minute, second,
1649 microsecond, tzinfo, fold=fold)
1650
1651 def _local_timezone(self):
1652 if self.tzinfo is None:
1653 ts = self._mktime()
1654 else:
1655 ts = (self - _EPOCH) // timedelta(seconds=1)
1656 localtm = _time.localtime(ts)
1657 local = datetime(*localtm[:6])
1658 try:
1659 # Extract TZ data if available
1660 gmtoff = localtm.tm_gmtoff
1661 zone = localtm.tm_zone
1662 except AttributeError:
1663 delta = local - datetime(*_time.gmtime(ts)[:6])
1664 zone = _time.strftime('%Z', localtm)
1665 tz = timezone(delta, zone)
1666 else:
1667 tz = timezone(timedelta(seconds=gmtoff), zone)
1668 return tz
1552 1669
1553 def astimezone(self, tz=None): 1670 def astimezone(self, tz=None):
1554 if tz is None: 1671 if tz is None:
1555 if self.tzinfo is None: 1672 tz = self._local_timezone()
1556 raise ValueError("astimezone() requires an aware datetime")
1557 ts = (self - _EPOCH) // timedelta(seconds=1)
1558 localtm = _time.localtime(ts)
1559 local = datetime(*localtm[:6])
1560 try:
1561 # Extract TZ data if available
1562 gmtoff = localtm.tm_gmtoff
1563 zone = localtm.tm_zone
1564 except AttributeError:
1565 # Compute UTC offset and compare with the value implied
1566 # by tm_isdst. If the values match, use the zone name
1567 # implied by tm_isdst.
1568 delta = local - datetime(*_time.gmtime(ts)[:6])
1569 dst = _time.daylight and localtm.tm_isdst > 0
1570 gmtoff = -(_time.altzone if dst else _time.timezone)
1571 if delta == timedelta(seconds=gmtoff):
1572 tz = timezone(delta, _time.tzname[dst])
1573 else:
1574 tz = timezone(delta)
1575 else:
1576 tz = timezone(timedelta(seconds=gmtoff), zone)
1577
1578 elif not isinstance(tz, tzinfo): 1673 elif not isinstance(tz, tzinfo):
1579 raise TypeError("tz argument must be an instance of tzinfo") 1674 raise TypeError("tz argument must be an instance of tzinfo")
1580 1675
1581 mytz = self.tzinfo 1676 mytz = self.tzinfo
1582 if mytz is None: 1677 if mytz is None:
1583 raise ValueError("astimezone() requires an aware datetime") 1678 mytz = self._local_timezone()
1584 1679
1585 if tz is mytz: 1680 if tz is mytz:
1586 return self 1681 return self
1587 1682
1588 # Convert self to UTC, and attach the new time zone object. 1683 # Convert self to UTC, and attach the new time zone object.
1589 myoffset = self.utcoffset() 1684 myoffset = mytz.utcoffset(self)
1590 if myoffset is None: 1685 if myoffset is None:
1591 raise ValueError("astimezone() requires an aware datetime") 1686 raise ValueError("astimezone() requires an aware datetime")
1592 utc = (self - myoffset).replace(tzinfo=tz) 1687 utc = (self - myoffset).replace(tzinfo=tz)
1593 1688
1594 # Convert from UTC to tz's local time. 1689 # Convert from UTC to tz's local time.
1595 return tz.fromutc(utc) 1690 return tz.fromutc(utc)
1596 1691
1597 # Ways to produce a string. 1692 # Ways to produce a string.
1598 1693
1599 def ctime(self): 1694 def ctime(self):
1600 "Return ctime() style string." 1695 "Return ctime() style string."
1601 weekday = self.toordinal() % 7 or 7 1696 weekday = self.toordinal() % 7 or 7
1602 return "%s %s %2d %02d:%02d:%02d %04d" % ( 1697 return "%s %s %2d %02d:%02d:%02d %04d" % (
1603 _DAYNAMES[weekday], 1698 _DAYNAMES[weekday],
1604 _MONTHNAMES[self._month], 1699 _MONTHNAMES[self._month],
1605 self._day, 1700 self._day,
1606 self._hour, self._minute, self._second, 1701 self._hour, self._minute, self._second,
1607 self._year) 1702 self._year)
1608 1703
1609 def isoformat(self, sep='T'): 1704 def isoformat(self, sep='T', timespec='auto'):
1610 """Return the time formatted according to ISO. 1705 """Return the time formatted according to ISO.
1611 1706
1612 This is 'YYYY-MM-DD HH:MM:SS.mmmmmm', or 'YYYY-MM-DD HH:MM:SS' if 1707 The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmm'.
1613 self.microsecond == 0. 1708 By default, the fractional part is omitted if self.microsecond == 0.
1614 1709
1615 If self.tzinfo is not None, the UTC offset is also attached, giving 1710 If self.tzinfo is not None, the UTC offset is also attached, giving
1616 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM' or 'YYYY-MM-DD HH:MM:SS+HH:MM'. 1711 giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM'.
1617 1712
1618 Optional argument sep specifies the separator between date and 1713 Optional argument sep specifies the separator between date and
1619 time, default 'T'. 1714 time, default 'T'.
1715
1716 The optional argument timespec specifies the number of additional
1717 terms of the time to include.
1620 """ 1718 """
1621 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) + 1719 s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
1622 _format_time(self._hour, self._minute, self._second, 1720 _format_time(self._hour, self._minute, self._second,
1623 self._microsecond)) 1721 self._microsecond, timespec))
1722
1624 off = self.utcoffset() 1723 off = self.utcoffset()
1625 if off is not None: 1724 if off is not None:
1626 if off.days < 0: 1725 if off.days < 0:
1627 sign = "-" 1726 sign = "-"
1628 off = -off 1727 off = -off
1629 else: 1728 else:
1630 sign = "+" 1729 sign = "+"
1631 hh, mm = divmod(off, timedelta(hours=1)) 1730 hh, mm = divmod(off, timedelta(hours=1))
1632 assert not mm % timedelta(minutes=1), "whole minute" 1731 mm, ss = divmod(mm, timedelta(minutes=1))
1633 mm //= timedelta(minutes=1)
1634 s += "%s%02d:%02d" % (sign, hh, mm) 1732 s += "%s%02d:%02d" % (sign, hh, mm)
1733 if ss:
1734 assert not ss.microseconds
1735 s += ":%02d" % ss.seconds
1635 return s 1736 return s
1636 1737
1637 def __repr__(self): 1738 def __repr__(self):
1638 """Convert to formal string, for repr().""" 1739 """Convert to formal string, for repr()."""
1639 L = [self._year, self._month, self._day, # These are never zero 1740 L = [self._year, self._month, self._day, # These are never zero
1640 self._hour, self._minute, self._second, self._microsecond] 1741 self._hour, self._minute, self._second, self._microsecond]
1641 if L[-1] == 0: 1742 if L[-1] == 0:
1642 del L[-1] 1743 del L[-1]
1643 if L[-1] == 0: 1744 if L[-1] == 0:
1644 del L[-1] 1745 del L[-1]
1645 s = "%s.%s(%s)" % (self.__class__.__module__, 1746 s = "%s.%s(%s)" % (self.__class__.__module__,
1646 self.__class__.__qualname__, 1747 self.__class__.__qualname__,
1647 ", ".join(map(str, L))) 1748 ", ".join(map(str, L)))
1648 if self._tzinfo is not None: 1749 if self._tzinfo is not None:
1649 assert s[-1:] == ")" 1750 assert s[-1:] == ")"
1650 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")" 1751 s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
1752 if self._fold:
1753 assert s[-1:] == ")"
1754 s = s[:-1] + ", fold=1)"
1651 return s 1755 return s
1652 1756
1653 def __str__(self): 1757 def __str__(self):
1654 "Convert to string, for str()." 1758 "Convert to string, for str()."
1655 return self.isoformat(sep=' ') 1759 return self.isoformat(sep=' ')
1656 1760
1657 @classmethod 1761 @classmethod
1658 def strptime(cls, date_string, format): 1762 def strptime(cls, date_string, format):
1659 'string, format -> new datetime parsed from a string (like time.strptime ()).' 1763 'string, format -> new datetime parsed from a string (like time.strptime ()).'
1660 import _strptime 1764 import _strptime
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
1743 assert isinstance(other, datetime) 1847 assert isinstance(other, datetime)
1744 mytz = self._tzinfo 1848 mytz = self._tzinfo
1745 ottz = other._tzinfo 1849 ottz = other._tzinfo
1746 myoff = otoff = None 1850 myoff = otoff = None
1747 1851
1748 if mytz is ottz: 1852 if mytz is ottz:
1749 base_compare = True 1853 base_compare = True
1750 else: 1854 else:
1751 myoff = self.utcoffset() 1855 myoff = self.utcoffset()
1752 otoff = other.utcoffset() 1856 otoff = other.utcoffset()
1857 # Assume that allow_mixed means that we are called from __eq__
1858 if allow_mixed:
1859 if myoff != self.replace(fold=not self.fold).utcoffset():
1860 return 2
1861 if otoff != other.replace(fold=not other.fold).utcoffset():
1862 return 2
1753 base_compare = myoff == otoff 1863 base_compare = myoff == otoff
1754 1864
1755 if base_compare: 1865 if base_compare:
1756 return _cmp((self._year, self._month, self._day, 1866 return _cmp((self._year, self._month, self._day,
1757 self._hour, self._minute, self._second, 1867 self._hour, self._minute, self._second,
1758 self._microsecond), 1868 self._microsecond),
1759 (other._year, other._month, other._day, 1869 (other._year, other._month, other._day,
1760 other._hour, other._minute, other._second, 1870 other._hour, other._minute, other._second,
1761 other._microsecond)) 1871 other._microsecond))
1762 if myoff is None or otoff is None: 1872 if myoff is None or otoff is None:
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1810 myoff = self.utcoffset() 1920 myoff = self.utcoffset()
1811 otoff = other.utcoffset() 1921 otoff = other.utcoffset()
1812 if myoff == otoff: 1922 if myoff == otoff:
1813 return base 1923 return base
1814 if myoff is None or otoff is None: 1924 if myoff is None or otoff is None:
1815 raise TypeError("cannot mix naive and timezone-aware time") 1925 raise TypeError("cannot mix naive and timezone-aware time")
1816 return base + otoff - myoff 1926 return base + otoff - myoff
1817 1927
1818 def __hash__(self): 1928 def __hash__(self):
1819 if self._hashcode == -1: 1929 if self._hashcode == -1:
1820 tzoff = self.utcoffset() 1930 if self.fold:
1931 t = self.replace(fold=0)
1932 else:
1933 t = self
1934 tzoff = t.utcoffset()
1821 if tzoff is None: 1935 if tzoff is None:
1822 self._hashcode = hash(self._getstate()[0]) 1936 self._hashcode = hash(t._getstate()[0])
1823 else: 1937 else:
1824 days = _ymd2ord(self.year, self.month, self.day) 1938 days = _ymd2ord(self.year, self.month, self.day)
1825 seconds = self.hour * 3600 + self.minute * 60 + self.second 1939 seconds = self.hour * 3600 + self.minute * 60 + self.second
1826 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff) 1940 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1827 return self._hashcode 1941 return self._hashcode
1828 1942
1829 # Pickle support. 1943 # Pickle support.
1830 1944
1831 def _getstate(self): 1945 def _getstate(self, protocol=3):
1832 yhi, ylo = divmod(self._year, 256) 1946 yhi, ylo = divmod(self._year, 256)
1833 us2, us3 = divmod(self._microsecond, 256) 1947 us2, us3 = divmod(self._microsecond, 256)
1834 us1, us2 = divmod(us2, 256) 1948 us1, us2 = divmod(us2, 256)
1835 basestate = bytes([yhi, ylo, self._month, self._day, 1949 m = self._month
1950 if self._fold and protocol > 3:
1951 m += 128
1952 basestate = bytes([yhi, ylo, m, self._day,
1836 self._hour, self._minute, self._second, 1953 self._hour, self._minute, self._second,
1837 us1, us2, us3]) 1954 us1, us2, us3])
1838 if self._tzinfo is None: 1955 if self._tzinfo is None:
1839 return (basestate,) 1956 return (basestate,)
1840 else: 1957 else:
1841 return (basestate, self._tzinfo) 1958 return (basestate, self._tzinfo)
1842 1959
1843 def __setstate(self, string, tzinfo): 1960 def __setstate(self, string, tzinfo):
1844 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class): 1961 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1845 raise TypeError("bad tzinfo state arg") 1962 raise TypeError("bad tzinfo state arg")
1846 (yhi, ylo, self._month, self._day, self._hour, 1963 (yhi, ylo, m, self._day, self._hour,
1847 self._minute, self._second, us1, us2, us3) = string 1964 self._minute, self._second, us1, us2, us3) = string
1965 if m > 127:
1966 self._fold = 1
1967 self._month = m - 128
1968 else:
1969 self._fold = 0
1970 self._month = m
1848 self._year = yhi * 256 + ylo 1971 self._year = yhi * 256 + ylo
1849 self._microsecond = (((us1 << 8) | us2) << 8) | us3 1972 self._microsecond = (((us1 << 8) | us2) << 8) | us3
1850 self._tzinfo = tzinfo 1973 self._tzinfo = tzinfo
1851 1974
1852 def __reduce__(self): 1975 def __reduce_ex__(self, protocol):
1853 return (self.__class__, self._getstate()) 1976 return (self.__class__, self._getstate(protocol))
1854 1977
1855 1978
1856 datetime.min = datetime(1, 1, 1) 1979 datetime.min = datetime(1, 1, 1)
1857 datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999) 1980 datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1858 datetime.resolution = timedelta(microseconds=1) 1981 datetime.resolution = timedelta(microseconds=1)
1859 1982
1860 1983
1861 def _isoweek1monday(year): 1984 def _isoweek1monday(year):
1862 # Helper to calculate the day number of the Monday starting week 1 1985 # Helper to calculate the day number of the Monday starting week 1
1863 # XXX This could be done more efficiently 1986 # XXX This could be done more efficiently
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
2176 # 2299 #
2177 # In any case, it's clear that the default fromutc() is strong enough to handle 2300 # In any case, it's clear that the default fromutc() is strong enough to handle
2178 # "almost all" time zones: so long as the standard offset is invariant, it 2301 # "almost all" time zones: so long as the standard offset is invariant, it
2179 # doesn't matter if daylight time transition points change from year to year, or 2302 # doesn't matter if daylight time transition points change from year to year, or
2180 # if daylight time is skipped in some years; it doesn't matter how large or 2303 # if daylight time is skipped in some years; it doesn't matter how large or
2181 # small dst() may get within its bounds; and it doesn't even matter if some 2304 # small dst() may get within its bounds; and it doesn't even matter if some
2182 # perverse time zone returns a negative dst()). So a breaking case must be 2305 # perverse time zone returns a negative dst()). So a breaking case must be
2183 # pretty bizarre, and a tzinfo subclass can override fromutc() if it is. 2306 # pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
2184 2307
2185 try: 2308 try:
2309 raise ImportError
2186 from _datetime import * 2310 from _datetime import *
2187 except ImportError: 2311 except ImportError:
2188 pass 2312 pass
2189 else: 2313 else:
2190 # Clean up unused names 2314 # Clean up unused names
2191 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y, 2315 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2192 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time, 2316 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2193 _check_date_fields, _check_int_field, _check_time_fields, 2317 _check_date_fields, _check_int_field, _check_time_fields,
2194 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror, 2318 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2195 _date_class, _days_before_month, _days_before_year, _days_in_month, 2319 _date_class, _days_before_month, _days_before_year, _days_in_month,
2196 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd, 2320 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2197 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord) 2321 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
2198 # XXX Since import * above excludes names that start with _, 2322 # XXX Since import * above excludes names that start with _,
2199 # docstring does not get overwritten. In the future, it may be 2323 # docstring does not get overwritten. In the future, it may be
2200 # appropriate to maintain a single module level docstring and 2324 # appropriate to maintain a single module level docstring and
2201 # remove the following line. 2325 # remove the following line.
2202 from _datetime import __doc__ 2326 from _datetime import __doc__
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+