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

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 10
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 140
141 # Now the year and month are correct, and n is the offset from the 141 # Now the year and month are correct, and n is the offset from the
142 # start of that month: we're done! 142 # start of that month: we're done!
143 return year, month, n+1 143 return year, month, n+1
144 144
145 # Month and day names. For localized versions, see the calendar module. 145 # Month and day names. For localized versions, see the calendar module.
146 _MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun", 146 _MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
147 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 147 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
148 _DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] 148 _DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
149 149
150 datetime_re = re.compile(
151 r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
152 r'[T ](?P<hour>\d{2}):(?P<minute>\d{2}):'
153 r'(?P<second>\d{2})(?:(?P<microsecond>\.\d{1,7})\d*)?'
154 r'(?P<tzinfo>Z|[+-]\d{2}:\d{2})?$'
155 )
156 150
157 def _build_struct_time(y, m, d, hh, mm, ss, dstflag): 151 def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
158 wday = (_ymd2ord(y, m, d) + 6) % 7 152 wday = (_ymd2ord(y, m, d) + 6) % 7
159 dnum = _days_before_month(y, m) + d 153 dnum = _days_before_month(y, m) + d
160 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))
161 155
162 def _format_time(hh, mm, ss, us): 156 def _format_time(hh, mm, ss, us, timespec='auto'):
163 # Skip trailing microseconds when us==0. 157 specs = {
164 result = "%02d:%02d:%02d" % (hh, mm, ss) 158 'hours': '{:02d}',
165 if us: 159 'minutes': '{:02d}:{:02d}',
166 result += ".%06d" % us 160 'seconds': '{:02d}:{:02d}:{:02d}',
167 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)
168 176
169 # Correctly substitute for %z and %Z escapes in strftime formats. 177 # Correctly substitute for %z and %Z escapes in strftime formats.
170 def _wrap_strftime(object, format, timetuple): 178 def _wrap_strftime(object, format, timetuple):
171 # Don't call utcoffset() or tzname() unless actually needed. 179 # Don't call utcoffset() or tzname() unless actually needed.
172 freplace = None # the string to use for %f 180 freplace = None # the string to use for %f
173 zreplace = None # the string to use for %z 181 zreplace = None # the string to use for %z
174 Zreplace = None # the string to use for %Z 182 Zreplace = None # the string to use for %Z
175 183
176 # Scan format for %z and %Z escapes, replacing as needed. 184 # Scan format for %z and %Z escapes, replacing as needed.
177 newformat = [] 185 newformat = []
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 # If offset is None, returns None. 244 # If offset is None, returns None.
237 # 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.
238 # 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.
239 def _check_utc_offset(name, offset): 247 def _check_utc_offset(name, offset):
240 assert name in ("utcoffset", "dst") 248 assert name in ("utcoffset", "dst")
241 if offset is None: 249 if offset is None:
242 return 250 return
243 if not isinstance(offset, timedelta): 251 if not isinstance(offset, timedelta):
244 raise TypeError("tzinfo.%s() must return None " 252 raise TypeError("tzinfo.%s() must return None "
245 "or timedelta, not '%s'" % (name, type(offset))) 253 "or timedelta, not '%s'" % (name, type(offset)))
246 if offset % timedelta(minutes=1) or offset.microseconds: 254 if offset.microseconds:
247 raise ValueError("tzinfo.%s() must return a whole number " 255 raise ValueError("tzinfo.%s() must return a whole number "
248 "of minutes, got %s" % (name, offset)) 256 "of seconds, got %s" % (name, offset))
249 if not -timedelta(1) < offset < timedelta(1): 257 if not -timedelta(1) < offset < timedelta(1):
250 raise ValueError("%s()=%s, must be must be strictly between " 258 raise ValueError("%s()=%s, must be strictly between "
251 "-timedelta(hours=24) and timedelta(hours=24)" % 259 "-timedelta(hours=24) and timedelta(hours=24)" %
252 (name, offset)) 260 (name, offset))
253 261
254 def _check_int_field(value): 262 def _check_int_field(value):
255 if isinstance(value, int): 263 if isinstance(value, int):
256 return value 264 return value
257 if not isinstance(value, float): 265 if not isinstance(value, float):
258 try: 266 try:
259 value = value.__int__() 267 value = value.__int__()
260 except AttributeError: 268 except AttributeError:
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 q, r = divmod(a, b) 323 q, r = divmod(a, b)
316 # 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.
317 # 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
318 # positive, 2 * r < b if b negative. 326 # positive, 2 * r < b if b negative.
319 r *= 2 327 r *= 2
320 greater_than_half = r > b if b > 0 else r < b 328 greater_than_half = r > b if b > 0 else r < b
321 if greater_than_half or r == b and q % 2 == 1: 329 if greater_than_half or r == b and q % 2 == 1:
322 q += 1 330 q += 1
323 331
324 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)
325 358
326 359
327 class timedelta: 360 class timedelta:
328 """Represent the difference between two datetime objects. 361 """Represent the difference between two datetime objects.
329 362
330 Supported operators: 363 Supported operators:
331 364
332 - add, subtract timedelta 365 - add, subtract timedelta
333 - unary plus, minus, abs 366 - unary plus, minus, abs
334 - compare to timedelta 367 - compare to timedelta
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 toordinal() 701 toordinal()
669 weekday() 702 weekday()
670 isoweekday(), isocalendar(), isoformat() 703 isoweekday(), isocalendar(), isoformat()
671 ctime() 704 ctime()
672 strftime() 705 strftime()
673 706
674 Properties (readonly): 707 Properties (readonly):
675 year, month, day 708 year, month, day
676 """ 709 """
677 __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)
678 713
679 def __new__(cls, year, month=None, day=None): 714 def __new__(cls, year, month=None, day=None):
680 """Constructor. 715 """Constructor.
681 716
682 Arguments: 717 Arguments:
683 718
684 year, month, day (required, base 1) 719 year, month, day (required, base 1)
685 """ 720 """
686 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 \
687 1 <= year[2] <= 12: 722 1 <= year[2] <= 12:
(...skipping 19 matching lines...) Expand all
707 return cls(y, m, d) 742 return cls(y, m, d)
708 743
709 @classmethod 744 @classmethod
710 def today(cls): 745 def today(cls):
711 "Construct a date from time.time()." 746 "Construct a date from time.time()."
712 t = _time.time() 747 t = _time.time()
713 return cls.fromtimestamp(t) 748 return cls.fromtimestamp(t)
714 749
715 @classmethod 750 @classmethod
716 def fromordinal(cls, n): 751 def fromordinal(cls, n):
717 """Contruct a date from a proleptic Gregorian ordinal. 752 """Construct a date from a proleptic Gregorian ordinal.
718 753
719 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
720 non-zero in the result. 755 non-zero in the result.
721 """ 756 """
722 y, m, d = _ord2ymd(n) 757 y, m, d = _ord2ymd(n)
723 return cls(y, m, d) 758 return cls(y, m, d)
759
760 @classmethod
761 def fromisoformat(cls, date_string):
762 """Constructs a date from an RFC 3339 string, a strict subset of ISO 860 1
763
764 Raises ValueError in case of ill-formatted or invalid string.
765 """
766 return _parse_isotime(cls, date_string)
724 767
725 # Conversions to string 768 # Conversions to string
726 769
727 def __repr__(self): 770 def __repr__(self):
728 """Convert to formal string, for repr(). 771 """Convert to formal string, for repr().
729 772
730 >>> dt = datetime(2010, 1, 1) 773 >>> dt = datetime(2010, 1, 1)
731 >>> repr(dt) 774 >>> repr(dt)
732 'datetime.datetime(2010, 1, 1, 0, 0)' 775 'datetime.datetime(2010, 1, 1, 0, 0)'
733 776
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
916 week1monday = _isoweek1monday(year) 959 week1monday = _isoweek1monday(year)
917 week, day = divmod(today - week1monday, 7) 960 week, day = divmod(today - week1monday, 7)
918 elif week >= 52: 961 elif week >= 52:
919 if today >= _isoweek1monday(year+1): 962 if today >= _isoweek1monday(year+1):
920 year += 1 963 year += 1
921 week = 0 964 week = 0
922 return year, week+1, day+1 965 return year, week+1, day+1
923 966
924 # Pickle support. 967 # Pickle support.
925 968
926 def _getstate(self): 969 def _getstate(self, protocol=3):
927 yhi, ylo = divmod(self._year, 256) 970 yhi, ylo = divmod(self._year, 256)
928 return bytes([yhi, ylo, self._month, self._day]), 971 return bytes([yhi, ylo, self._month, self._day]),
929 972
930 def __setstate(self, string): 973 def __setstate(self, string):
931 yhi, ylo, self._month, self._day = string 974 yhi, ylo, self._month, self._day = string
932 self._year = yhi * 256 + ylo 975 self._year = yhi * 256 + ylo
933 976
934 def __reduce__(self): 977 def __reduce_ex__(self, protocol):
935 return (self.__class__, self._getstate()) 978 return (self.__class__, self._getstate(protocol))
936 979
937 _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
938 981
939 date.min = date(1, 1, 1) 982 date.min = date(1, 1, 1)
940 date.max = date(9999, 12, 31) 983 date.max = date(9999, 12, 31)
941 date.resolution = timedelta(days=1) 984 date.resolution = timedelta(days=1)
985
942 986
943 class tzinfo: 987 class tzinfo:
944 """Abstract base class for time zone info classes. 988 """Abstract base class for time zone info classes.
945 989
946 Subclasses must override the name(), utcoffset() and dst() methods. 990 Subclasses must override the name(), utcoffset() and dst() methods.
947 """ 991 """
948 __slots__ = () 992 __slots__ = ()
949 993
950 def tzname(self, dt): 994 def tzname(self, dt):
951 "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
1003 state = getstate() 1047 state = getstate()
1004 else: 1048 else:
1005 state = getattr(self, "__dict__", None) or None 1049 state = getattr(self, "__dict__", None) or None
1006 if state is None: 1050 if state is None:
1007 return (self.__class__, args) 1051 return (self.__class__, args)
1008 else: 1052 else:
1009 return (self.__class__, args, state) 1053 return (self.__class__, args, state)
1010 1054
1011 _tzinfo_class = tzinfo 1055 _tzinfo_class = tzinfo
1012 1056
1057
1013 class time: 1058 class time:
1014 """Time with time zone. 1059 """Time with time zone.
1015 1060
1016 Constructors: 1061 Constructors:
1017 1062
1018 __new__() 1063 __new__()
1019 1064
1020 Operators: 1065 Operators:
1021 1066
1022 __repr__, __str__ 1067 __repr__, __str__
1023 __eq__, __le__, __lt__, __ge__, __gt__, __hash__ 1068 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
1024 1069
1025 Methods: 1070 Methods:
1026 1071
1027 strftime() 1072 strftime()
1028 isoformat() 1073 isoformat()
1029 utcoffset() 1074 utcoffset()
1030 tzname() 1075 tzname()
1031 dst() 1076 dst()
1032 1077
1033 Properties (readonly): 1078 Properties (readonly):
1034 hour, minute, second, microsecond, tzinfo 1079 hour, minute, second, microsecond, tzinfo, fold
1035 """ 1080 """
1036 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hash code' 1081 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hash code', '_fold'
1037 1082
1038 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):
1039 """Constructor. 1089 """Constructor.
1040 1090
1041 Arguments: 1091 Arguments:
1042 1092
1043 hour, minute (required) 1093 hour, minute (required)
1044 second, microsecond (default to zero) 1094 second, microsecond (default to zero)
1045 tzinfo (default to None) 1095 tzinfo (default to None)
1096 fold (keyword only, default to True)
1046 """ 1097 """
1047 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:
1048 # Pickle support 1099 # Pickle support
1049 self = object.__new__(cls) 1100 self = object.__new__(cls)
1050 self.__setstate(hour, minute or None) 1101 self.__setstate(hour, minute or None)
1051 self._hashcode = -1 1102 self._hashcode = -1
1052 return self 1103 return self
1053 hour, minute, second, microsecond = _check_time_fields( 1104 hour, minute, second, microsecond = _check_time_fields(
1054 hour, minute, second, microsecond) 1105 hour, minute, second, microsecond)
1055 _check_tzinfo_arg(tzinfo) 1106 _check_tzinfo_arg(tzinfo)
1056 self = object.__new__(cls) 1107 self = object.__new__(cls)
1057 self._hour = hour 1108 self._hour = hour
1058 self._minute = minute 1109 self._minute = minute
1059 self._second = second 1110 self._second = second
1060 self._microsecond = microsecond 1111 self._microsecond = microsecond
1061 self._tzinfo = tzinfo 1112 self._tzinfo = tzinfo
1062 self._hashcode = -1 1113 self._hashcode = -1
1114 self._fold = fold
1063 return self 1115 return self
1116
1117 @classmethod
1118 def fromisoformat(cls, time_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.
1123 """
1124 return _parse_isotime(cls, time_string)
1064 1125
1065 # Read-only field accessors 1126 # Read-only field accessors
1066 @property 1127 @property
1067 def hour(self): 1128 def hour(self):
1068 """hour (0-23)""" 1129 """hour (0-23)"""
1069 return self._hour 1130 return self._hour
1070 1131
1071 @property 1132 @property
1072 def minute(self): 1133 def minute(self):
1073 """minute (0-59)""" 1134 """minute (0-59)"""
1074 return self._minute 1135 return self._minute
1075 1136
1076 @property 1137 @property
1077 def second(self): 1138 def second(self):
1078 """second (0-59)""" 1139 """second (0-59)"""
1079 return self._second 1140 return self._second
1080 1141
1081 @property 1142 @property
1082 def microsecond(self): 1143 def microsecond(self):
1083 """microsecond (0-999999)""" 1144 """microsecond (0-999999)"""
1084 return self._microsecond 1145 return self._microsecond
1085 1146
1086 @property 1147 @property
1087 def tzinfo(self): 1148 def tzinfo(self):
1088 """timezone info object""" 1149 """timezone info object"""
1089 return self._tzinfo 1150 return self._tzinfo
1151
1152 @property
1153 def fold(self):
1154 return self._fold
1090 1155
1091 # Standard conversions, __hash__ (and helpers) 1156 # Standard conversions, __hash__ (and helpers)
1092 1157
1093 # Comparisons of time objects with other. 1158 # Comparisons of time objects with other.
1094 1159
1095 def __eq__(self, other): 1160 def __eq__(self, other):
1096 if isinstance(other, time): 1161 if isinstance(other, time):
1097 return self._cmp(other, allow_mixed=True) == 0 1162 return self._cmp(other, allow_mixed=True) == 0
1098 else: 1163 else:
1099 return False 1164 return False
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1146 else: 1211 else:
1147 raise TypeError("cannot compare naive and aware times") 1212 raise TypeError("cannot compare naive and aware times")
1148 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1) 1213 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1149 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1) 1214 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1150 return _cmp((myhhmm, self._second, self._microsecond), 1215 return _cmp((myhhmm, self._second, self._microsecond),
1151 (othhmm, other._second, other._microsecond)) 1216 (othhmm, other._second, other._microsecond))
1152 1217
1153 def __hash__(self): 1218 def __hash__(self):
1154 """Hash.""" 1219 """Hash."""
1155 if self._hashcode == -1: 1220 if self._hashcode == -1:
1156 tzoff = self.utcoffset() 1221 if self.fold:
1222 t = self.replace(fold=0)
1223 else:
1224 t = self
1225 tzoff = t.utcoffset()
1157 if not tzoff: # zero or None 1226 if not tzoff: # zero or None
1158 self._hashcode = hash(self._getstate()[0]) 1227 self._hashcode = hash(t._getstate()[0])
1159 else: 1228 else:
1160 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff, 1229 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1161 timedelta(hours=1)) 1230 timedelta(hours=1))
1162 assert not m % timedelta(minutes=1), "whole minute" 1231 assert not m % timedelta(minutes=1), "whole minute"
1163 m //= timedelta(minutes=1) 1232 m //= timedelta(minutes=1)
1164 if 0 <= h < 24: 1233 if 0 <= h < 24:
1165 self._hashcode = hash(time(h, m, self.second, self.microseco nd)) 1234 self._hashcode = hash(time(h, m, self.second, self.microseco nd))
1166 else: 1235 else:
1167 self._hashcode = hash((h, m, self.second, self.microsecond)) 1236 self._hashcode = hash((h, m, self.second, self.microsecond))
1168 return self._hashcode 1237 return self._hashcode
1169 1238
1170 # Conversion to string 1239 # Conversion to string
1171 1240
1172 def _tzstr(self, sep=":"): 1241 def _tzstr(self, sep=":"):
1173 """Return formatted timezone offset (+xx:xx) or None.""" 1242 """Return formatted timezone offset (+xx:xx) or None."""
1174 off = self.utcoffset() 1243 off = self.utcoffset()
1175 if off is not None: 1244 if off is not None:
1176 if off.days < 0: 1245 if off.days < 0:
1177 sign = "-" 1246 sign = "-"
1178 off = -off 1247 off = -off
1179 else: 1248 else:
1180 sign = "+" 1249 sign = "+"
1181 hh, mm = divmod(off, timedelta(hours=1)) 1250 hh, mm = divmod(off, timedelta(hours=1))
1182 assert not mm % timedelta(minutes=1), "whole minute" 1251 mm, ss = divmod(mm, timedelta(minutes=1))
1183 mm //= timedelta(minutes=1)
1184 assert 0 <= hh < 24 1252 assert 0 <= hh < 24
1185 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
1186 return off 1256 return off
1187 1257
1188 def __repr__(self): 1258 def __repr__(self):
1189 """Convert to formal string, for repr().""" 1259 """Convert to formal string, for repr()."""
1190 if self._microsecond != 0: 1260 if self._microsecond != 0:
1191 s = ", %d, %d" % (self._second, self._microsecond) 1261 s = ", %d, %d" % (self._second, self._microsecond)
1192 elif self._second != 0: 1262 elif self._second != 0:
1193 s = ", %d" % self._second 1263 s = ", %d" % self._second
1194 else: 1264 else:
1195 s = "" 1265 s = ""
1196 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__, 1266 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1197 self.__class__.__qualname__, 1267 self.__class__.__qualname__,
1198 self._hour, self._minute, s) 1268 self._hour, self._minute, s)
1199 if self._tzinfo is not None: 1269 if self._tzinfo is not None:
1200 assert s[-1:] == ")" 1270 assert s[-1:] == ")"
1201 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)"
1202 return s 1275 return s
1203 1276
1204 def isoformat(self): 1277 def isoformat(self, timespec='auto'):
1205 """Return the time formatted according to ISO. 1278 """Return the time formatted according to ISO.
1206 1279
1207 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
1208 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.
1209 """ 1285 """
1210 s = _format_time(self._hour, self._minute, self._second, 1286 s = _format_time(self._hour, self._minute, self._second,
1211 self._microsecond) 1287 self._microsecond, timespec)
1212 tz = self._tzstr() 1288 tz = self._tzstr()
1213 if tz: 1289 if tz:
1214 s += tz 1290 s += tz
1215 return s 1291 return s
1216 1292
1217 __str__ = isoformat 1293 __str__ = isoformat
1218 1294
1219 def strftime(self, fmt): 1295 def strftime(self, fmt):
1220 """Format using strftime(). The date part of the timestamp passed 1296 """Format using strftime(). The date part of the timestamp passed
1221 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
1267 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
1268 info. 1344 info.
1269 """ 1345 """
1270 if self._tzinfo is None: 1346 if self._tzinfo is None:
1271 return None 1347 return None
1272 offset = self._tzinfo.dst(None) 1348 offset = self._tzinfo.dst(None)
1273 _check_utc_offset("dst", offset) 1349 _check_utc_offset("dst", offset)
1274 return offset 1350 return offset
1275 1351
1276 def replace(self, hour=None, minute=None, second=None, microsecond=None, 1352 def replace(self, hour=None, minute=None, second=None, microsecond=None,
1277 tzinfo=True): 1353 tzinfo=True, *, fold=None):
1278 """Return a new time with new values for the specified fields.""" 1354 """Return a new time with new values for the specified fields."""
1279 if hour is None: 1355 if hour is None:
1280 hour = self.hour 1356 hour = self.hour
1281 if minute is None: 1357 if minute is None:
1282 minute = self.minute 1358 minute = self.minute
1283 if second is None: 1359 if second is None:
1284 second = self.second 1360 second = self.second
1285 if microsecond is None: 1361 if microsecond is None:
1286 microsecond = self.microsecond 1362 microsecond = self.microsecond
1287 if tzinfo is True: 1363 if tzinfo is True:
1288 tzinfo = self.tzinfo 1364 tzinfo = self.tzinfo
1289 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)
1290 1368
1291 # Pickle support. 1369 # Pickle support.
1292 1370
1293 def _getstate(self): 1371 def _getstate(self, protocol=3):
1294 us2, us3 = divmod(self._microsecond, 256) 1372 us2, us3 = divmod(self._microsecond, 256)
1295 us1, us2 = divmod(us2, 256) 1373 us1, us2 = divmod(us2, 256)
1296 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,
1297 us1, us2, us3]) 1378 us1, us2, us3])
1298 if self._tzinfo is None: 1379 if self._tzinfo is None:
1299 return (basestate,) 1380 return (basestate,)
1300 else: 1381 else:
1301 return (basestate, self._tzinfo) 1382 return (basestate, self._tzinfo)
1302 1383
1303 def __setstate(self, string, tzinfo): 1384 def __setstate(self, string, tzinfo):
1304 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class): 1385 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1305 raise TypeError("bad tzinfo state arg") 1386 raise TypeError("bad tzinfo state arg")
1306 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
1307 self._microsecond = (((us1 << 8) | us2) << 8) | us3 1394 self._microsecond = (((us1 << 8) | us2) << 8) | us3
1308 self._tzinfo = tzinfo 1395 self._tzinfo = tzinfo
1309 1396
1310 def __reduce__(self): 1397 def __reduce_ex__(self, protocol):
1311 return (time, self._getstate()) 1398 return (time, self._getstate(protocol))
1312 1399
1313 _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
1314 1401
1315 time.min = time(0, 0, 0) 1402 time.min = time(0, 0, 0)
1316 time.max = time(23, 59, 59, 999999) 1403 time.max = time(23, 59, 59, 999999)
1317 time.resolution = timedelta(microseconds=1) 1404 time.resolution = timedelta(microseconds=1)
1318 1405
1319 class datetime(date): 1406 class datetime(date):
1320 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo] ]]]]) 1407 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo] ]]]])
1321 1408
1322 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
1323 instance of a tzinfo subclass. The remaining arguments may be ints. 1410 instance of a tzinfo subclass. The remaining arguments may be ints.
1324 """ 1411 """
1325 __slots__ = date.__slots__ + time.__slots__ 1412 __slots__ = date.__slots__ + time.__slots__
1326 1413
1414 _isore = re.compile(date._isore.pattern[:-1] + r'[T ]' +
1415 time._isore.pattern, re.ASCII|re.IGNORECASE)
1416
1327 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,
1328 microsecond=0, tzinfo=None): 1418 microsecond=0, tzinfo=None, *, fold=0):
1329 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:
1330 # Pickle support 1420 # Pickle support
1331 self = object.__new__(cls) 1421 self = object.__new__(cls)
1332 self.__setstate(year, month) 1422 self.__setstate(year, month)
1333 self._hashcode = -1 1423 self._hashcode = -1
1334 return self 1424 return self
1335 year, month, day = _check_date_fields(year, month, day) 1425 year, month, day = _check_date_fields(year, month, day)
1336 hour, minute, second, microsecond = _check_time_fields( 1426 hour, minute, second, microsecond = _check_time_fields(
1337 hour, minute, second, microsecond) 1427 hour, minute, second, microsecond)
1338 _check_tzinfo_arg(tzinfo) 1428 _check_tzinfo_arg(tzinfo)
1339 self = object.__new__(cls) 1429 self = object.__new__(cls)
1340 self._year = year 1430 self._year = year
1341 self._month = month 1431 self._month = month
1342 self._day = day 1432 self._day = day
1343 self._hour = hour 1433 self._hour = hour
1344 self._minute = minute 1434 self._minute = minute
1345 self._second = second 1435 self._second = second
1346 self._microsecond = microsecond 1436 self._microsecond = microsecond
1347 self._tzinfo = tzinfo 1437 self._tzinfo = tzinfo
1348 self._hashcode = -1 1438 self._hashcode = -1
1439 self._fold = fold
1349 return self 1440 return self
1350 1441
1351 # Read-only field accessors 1442 # Read-only field accessors
1352 @property 1443 @property
1353 def hour(self): 1444 def hour(self):
1354 """hour (0-23)""" 1445 """hour (0-23)"""
1355 return self._hour 1446 return self._hour
1356 1447
1357 @property 1448 @property
1358 def minute(self): 1449 def minute(self):
1359 """minute (0-59)""" 1450 """minute (0-59)"""
1360 return self._minute 1451 return self._minute
1361 1452
1362 @property 1453 @property
1363 def second(self): 1454 def second(self):
1364 """second (0-59)""" 1455 """second (0-59)"""
1365 return self._second 1456 return self._second
1366 1457
1367 @property 1458 @property
1368 def microsecond(self): 1459 def microsecond(self):
1369 """microsecond (0-999999)""" 1460 """microsecond (0-999999)"""
1370 return self._microsecond 1461 return self._microsecond
1371 1462
1372 @property 1463 @property
1373 def tzinfo(self): 1464 def tzinfo(self):
1374 """timezone info object""" 1465 """timezone info object"""
1375 return self._tzinfo 1466 return self._tzinfo
1467
1468 @property
1469 def fold(self):
1470 return self._fold
1376 1471
1377 @classmethod 1472 @classmethod
1378 def _fromtimestamp(cls, t, utc, tz): 1473 def _fromtimestamp(cls, t, utc, tz):
1379 """Construct a datetime from a POSIX timestamp (like time.time()). 1474 """Construct a datetime from a POSIX timestamp (like time.time()).
1380 1475
1381 A timezone info object may be passed in as well. 1476 A timezone info object may be passed in as well.
1382 """ 1477 """
1383 frac, t = _math.modf(t) 1478 frac, t = _math.modf(t)
1384 us = round(frac * 1e6) 1479 us = round(frac * 1e6)
1385 if us >= 1000000: 1480 if us >= 1000000:
1386 t += 1 1481 t += 1
1387 us -= 1000000 1482 us -= 1000000
1388 elif us < 0: 1483 elif us < 0:
1389 t -= 1 1484 t -= 1
1390 us += 1000000 1485 us += 1000000
1391 1486
1392 converter = _time.gmtime if utc else _time.localtime 1487 converter = _time.gmtime if utc else _time.localtime
1393 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) 1488 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1394 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
1395 return cls(y, m, d, hh, mm, ss, us, tz) 1490 result = cls(y, m, d, hh, mm, ss, us, tz)
1396 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
1507
1397 @classmethod 1508 @classmethod
1398 def fromtimestamp(cls, t, tz=None): 1509 def fromtimestamp(cls, t, tz=None):
1399 """Construct a datetime from a POSIX timestamp (like time.time()). 1510 """Construct a datetime from a POSIX timestamp (like time.time()).
1400 1511
1401 A timezone info object may be passed in as well. 1512 A timezone info object may be passed in as well.
1402 """ 1513 """
1403 _check_tzinfo_arg(tz) 1514 _check_tzinfo_arg(tz)
1404 1515
1405 result = cls._fromtimestamp(t, tz is not None, tz) 1516 return cls._fromtimestamp(t, tz is not None, tz)
1406 if tz is not None:
1407 result = tz.fromutc(result)
1408 return result
1409
1410 @classmethod
1411 def fromisoformat(cls, value):
1412 """Parses a string and return a datetime.datetime.
1413
1414 This function supports time zone offsets. When the input contains one,
1415 the output uses a timezone with a fixed offset from UTC.
1416 Microseconds values after 6 digits are discared.
1417
1418 Raises ValueError if the input is not well formatted or not a valid date time.
1419 """
1420 match = datetime_re.match(value)
1421 if not match:
1422 raise ValueError('invalid {} iso8601 string : {}'.format(cls.__name_ _, value))
1423 kw = match.groupdict()
1424 tzinfo = kw.pop('tzinfo')
1425 if tzinfo == 'Z':
1426 tzinfo = timezone.utc
1427 elif tzinfo is not None:
1428 offset_hours, offset_mins = tzinfo[1:].split(':')
1429 offset = timedelta(hours=int(offset_hours), minutes=int(offset_mins) )
1430 if tzinfo[0] == '-':
1431 offset = -offset
1432 tzinfo = timezone(offset)
1433 us = kw.pop('microsecond', None)
1434 kw = {k: int(v) for k, v in kw.items() if v is not None}
1435 if us:
1436 us = round(float(us), 6)
1437 kw['microsecond'] = int(us * 1e6)
1438 kw['tzinfo'] = tzinfo
1439 return cls(**kw)
1440 1517
1441 @classmethod 1518 @classmethod
1442 def utcfromtimestamp(cls, t): 1519 def utcfromtimestamp(cls, t):
1443 """Construct a naive UTC datetime from a POSIX timestamp.""" 1520 """Construct a naive UTC datetime from a POSIX timestamp."""
1444 return cls._fromtimestamp(t, True, None) 1521 return cls._fromtimestamp(t, True, None)
1445 1522
1446 @classmethod 1523 @classmethod
1447 def now(cls, tz=None): 1524 def now(cls, tz=None):
1448 "Construct a datetime from time.time() and optional time zone info." 1525 "Construct a datetime from time.time() and optional time zone info."
1449 t = _time.time() 1526 t = _time.time()
1450 return cls.fromtimestamp(t, tz) 1527 return cls.fromtimestamp(t, tz)
1451 1528
1452 @classmethod 1529 @classmethod
1453 def utcnow(cls): 1530 def utcnow(cls):
1454 "Construct a UTC datetime from time.time()." 1531 "Construct a UTC datetime from time.time()."
1455 t = _time.time() 1532 t = _time.time()
1456 return cls.utcfromtimestamp(t) 1533 return cls.utcfromtimestamp(t)
1457 1534
1458 @classmethod 1535 @classmethod
1459 def combine(cls, date, time): 1536 def combine(cls, date, time, tzinfo=True):
1460 "Construct a datetime from a given date and a given time." 1537 "Construct a datetime from a given date and a given time."
1461 if not isinstance(date, _date_class): 1538 if not isinstance(date, _date_class):
1462 raise TypeError("date argument must be a date instance") 1539 raise TypeError("date argument must be a date instance")
1463 if not isinstance(time, _time_class): 1540 if not isinstance(time, _time_class):
1464 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
1465 return cls(date.year, date.month, date.day, 1544 return cls(date.year, date.month, date.day,
1466 time.hour, time.minute, time.second, time.microsecond, 1545 time.hour, time.minute, time.second, time.microsecond,
1467 time.tzinfo) 1546 tzinfo, fold=time.fold)
1468 1547
1469 def timetuple(self): 1548 def timetuple(self):
1470 "Return local time tuple compatible with time.localtime()." 1549 "Return local time tuple compatible with time.localtime()."
1471 dst = self.dst() 1550 dst = self.dst()
1472 if dst is None: 1551 if dst is None:
1473 dst = -1 1552 dst = -1
1474 elif dst: 1553 elif dst:
1475 dst = 1 1554 dst = 1
1476 else: 1555 else:
1477 dst = 0 1556 dst = 0
1478 return _build_struct_time(self.year, self.month, self.day, 1557 return _build_struct_time(self.year, self.month, self.day,
1479 self.hour, self.minute, self.second, 1558 self.hour, self.minute, self.second,
1480 dst) 1559 dst)
1481 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
1482 def timestamp(self): 1596 def timestamp(self):
1483 "Return POSIX timestamp as float" 1597 "Return POSIX timestamp as float"
1484 if self._tzinfo is None: 1598 if self._tzinfo is None:
1485 return _time.mktime((self.year, self.month, self.day, 1599 s = self._mktime()
1486 self.hour, self.minute, self.second, 1600 return s + self.microsecond / 1e6
1487 -1, -1, -1)) + self.microsecond / 1e6
1488 else: 1601 else:
1489 return (self - _EPOCH).total_seconds() 1602 return (self - _EPOCH).total_seconds()
1490 1603
1491 def utctimetuple(self): 1604 def utctimetuple(self):
1492 "Return UTC time tuple compatible with time.gmtime()." 1605 "Return UTC time tuple compatible with time.gmtime()."
1493 offset = self.utcoffset() 1606 offset = self.utcoffset()
1494 if offset: 1607 if offset:
1495 self -= offset 1608 self -= offset
1496 y, m, d = self.year, self.month, self.day 1609 y, m, d = self.year, self.month, self.day
1497 hh, mm, ss = self.hour, self.minute, self.second 1610 hh, mm, ss = self.hour, self.minute, self.second
1498 return _build_struct_time(y, m, d, hh, mm, ss, 0) 1611 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1499 1612
1500 def date(self): 1613 def date(self):
1501 "Return the date part." 1614 "Return the date part."
1502 return date(self._year, self._month, self._day) 1615 return date(self._year, self._month, self._day)
1503 1616
1504 def time(self): 1617 def time(self):
1505 "Return the time part, with tzinfo None." 1618 "Return the time part, with tzinfo None."
1506 return time(self.hour, self.minute, self.second, self.microsecond) 1619 return time(self.hour, self.minute, self.second, self.microsecond, fold= self.fold)
1507 1620
1508 def timetz(self): 1621 def timetz(self):
1509 "Return the time part, with same tzinfo." 1622 "Return the time part, with same tzinfo."
1510 return time(self.hour, self.minute, self.second, self.microsecond, 1623 return time(self.hour, self.minute, self.second, self.microsecond,
1511 self._tzinfo) 1624 self._tzinfo, fold=self.fold)
1512 1625
1513 def replace(self, year=None, month=None, day=None, hour=None, 1626 def replace(self, year=None, month=None, day=None, hour=None,
1514 minute=None, second=None, microsecond=None, tzinfo=True): 1627 minute=None, second=None, microsecond=None, tzinfo=True,
1628 *, fold=None):
1515 """Return a new datetime with new values for the specified fields.""" 1629 """Return a new datetime with new values for the specified fields."""
1516 if year is None: 1630 if year is None:
1517 year = self.year 1631 year = self.year
1518 if month is None: 1632 if month is None:
1519 month = self.month 1633 month = self.month
1520 if day is None: 1634 if day is None:
1521 day = self.day 1635 day = self.day
1522 if hour is None: 1636 if hour is None:
1523 hour = self.hour 1637 hour = self.hour
1524 if minute is None: 1638 if minute is None:
1525 minute = self.minute 1639 minute = self.minute
1526 if second is None: 1640 if second is None:
1527 second = self.second 1641 second = self.second
1528 if microsecond is None: 1642 if microsecond is None:
1529 microsecond = self.microsecond 1643 microsecond = self.microsecond
1530 if tzinfo is True: 1644 if tzinfo is True:
1531 tzinfo = self.tzinfo 1645 tzinfo = self.tzinfo
1532 return datetime(year, month, day, hour, minute, second, microsecond, 1646 if fold is None:
1533 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
1534 1669
1535 def astimezone(self, tz=None): 1670 def astimezone(self, tz=None):
1536 if tz is None: 1671 if tz is None:
1537 if self.tzinfo is None: 1672 tz = self._local_timezone()
1538 raise ValueError("astimezone() requires an aware datetime")
1539 ts = (self - _EPOCH) // timedelta(seconds=1)
1540 localtm = _time.localtime(ts)
1541 local = datetime(*localtm[:6])
1542 try:
1543 # Extract TZ data if available
1544 gmtoff = localtm.tm_gmtoff
1545 zone = localtm.tm_zone
1546 except AttributeError:
1547 # Compute UTC offset and compare with the value implied
1548 # by tm_isdst. If the values match, use the zone name
1549 # implied by tm_isdst.
1550 delta = local - datetime(*_time.gmtime(ts)[:6])
1551 dst = _time.daylight and localtm.tm_isdst > 0
1552 gmtoff = -(_time.altzone if dst else _time.timezone)
1553 if delta == timedelta(seconds=gmtoff):
1554 tz = timezone(delta, _time.tzname[dst])
1555 else:
1556 tz = timezone(delta)
1557 else:
1558 tz = timezone(timedelta(seconds=gmtoff), zone)
1559
1560 elif not isinstance(tz, tzinfo): 1673 elif not isinstance(tz, tzinfo):
1561 raise TypeError("tz argument must be an instance of tzinfo") 1674 raise TypeError("tz argument must be an instance of tzinfo")
1562 1675
1563 mytz = self.tzinfo 1676 mytz = self.tzinfo
1564 if mytz is None: 1677 if mytz is None:
1565 raise ValueError("astimezone() requires an aware datetime") 1678 mytz = self._local_timezone()
1566 1679
1567 if tz is mytz: 1680 if tz is mytz:
1568 return self 1681 return self
1569 1682
1570 # Convert self to UTC, and attach the new time zone object. 1683 # Convert self to UTC, and attach the new time zone object.
1571 myoffset = self.utcoffset() 1684 myoffset = mytz.utcoffset(self)
1572 if myoffset is None: 1685 if myoffset is None:
1573 raise ValueError("astimezone() requires an aware datetime") 1686 raise ValueError("astimezone() requires an aware datetime")
1574 utc = (self - myoffset).replace(tzinfo=tz) 1687 utc = (self - myoffset).replace(tzinfo=tz)
1575 1688
1576 # Convert from UTC to tz's local time. 1689 # Convert from UTC to tz's local time.
1577 return tz.fromutc(utc) 1690 return tz.fromutc(utc)
1578 1691
1579 # Ways to produce a string. 1692 # Ways to produce a string.
1580 1693
1581 def ctime(self): 1694 def ctime(self):
1582 "Return ctime() style string." 1695 "Return ctime() style string."
1583 weekday = self.toordinal() % 7 or 7 1696 weekday = self.toordinal() % 7 or 7
1584 return "%s %s %2d %02d:%02d:%02d %04d" % ( 1697 return "%s %s %2d %02d:%02d:%02d %04d" % (
1585 _DAYNAMES[weekday], 1698 _DAYNAMES[weekday],
1586 _MONTHNAMES[self._month], 1699 _MONTHNAMES[self._month],
1587 self._day, 1700 self._day,
1588 self._hour, self._minute, self._second, 1701 self._hour, self._minute, self._second,
1589 self._year) 1702 self._year)
1590 1703
1591 def isoformat(self, sep='T'): 1704 def isoformat(self, sep='T', timespec='auto'):
1592 """Return the time formatted according to ISO. 1705 """Return the time formatted according to ISO.
1593 1706
1594 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'.
1595 self.microsecond == 0. 1708 By default, the fractional part is omitted if self.microsecond == 0.
1596 1709
1597 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
1598 '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'.
1599 1712
1600 Optional argument sep specifies the separator between date and 1713 Optional argument sep specifies the separator between date and
1601 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.
1602 """ 1718 """
1603 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) +
1604 _format_time(self._hour, self._minute, self._second, 1720 _format_time(self._hour, self._minute, self._second,
1605 self._microsecond)) 1721 self._microsecond, timespec))
1722
1606 off = self.utcoffset() 1723 off = self.utcoffset()
1607 if off is not None: 1724 if off is not None:
1608 if off.days < 0: 1725 if off.days < 0:
1609 sign = "-" 1726 sign = "-"
1610 off = -off 1727 off = -off
1611 else: 1728 else:
1612 sign = "+" 1729 sign = "+"
1613 hh, mm = divmod(off, timedelta(hours=1)) 1730 hh, mm = divmod(off, timedelta(hours=1))
1614 assert not mm % timedelta(minutes=1), "whole minute" 1731 mm, ss = divmod(mm, timedelta(minutes=1))
1615 mm //= timedelta(minutes=1)
1616 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
1617 return s 1736 return s
1618 1737
1619 def __repr__(self): 1738 def __repr__(self):
1620 """Convert to formal string, for repr().""" 1739 """Convert to formal string, for repr()."""
1621 L = [self._year, self._month, self._day, # These are never zero 1740 L = [self._year, self._month, self._day, # These are never zero
1622 self._hour, self._minute, self._second, self._microsecond] 1741 self._hour, self._minute, self._second, self._microsecond]
1623 if L[-1] == 0: 1742 if L[-1] == 0:
1624 del L[-1] 1743 del L[-1]
1625 if L[-1] == 0: 1744 if L[-1] == 0:
1626 del L[-1] 1745 del L[-1]
1627 s = "%s.%s(%s)" % (self.__class__.__module__, 1746 s = "%s.%s(%s)" % (self.__class__.__module__,
1628 self.__class__.__qualname__, 1747 self.__class__.__qualname__,
1629 ", ".join(map(str, L))) 1748 ", ".join(map(str, L)))
1630 if self._tzinfo is not None: 1749 if self._tzinfo is not None:
1631 assert s[-1:] == ")" 1750 assert s[-1:] == ")"
1632 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)"
1633 return s 1755 return s
1634 1756
1635 def __str__(self): 1757 def __str__(self):
1636 "Convert to string, for str()." 1758 "Convert to string, for str()."
1637 return self.isoformat(sep=' ') 1759 return self.isoformat(sep=' ')
1638 1760
1639 @classmethod 1761 @classmethod
1640 def strptime(cls, date_string, format): 1762 def strptime(cls, date_string, format):
1641 'string, format -> new datetime parsed from a string (like time.strptime ()).' 1763 'string, format -> new datetime parsed from a string (like time.strptime ()).'
1642 import _strptime 1764 import _strptime
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
1725 assert isinstance(other, datetime) 1847 assert isinstance(other, datetime)
1726 mytz = self._tzinfo 1848 mytz = self._tzinfo
1727 ottz = other._tzinfo 1849 ottz = other._tzinfo
1728 myoff = otoff = None 1850 myoff = otoff = None
1729 1851
1730 if mytz is ottz: 1852 if mytz is ottz:
1731 base_compare = True 1853 base_compare = True
1732 else: 1854 else:
1733 myoff = self.utcoffset() 1855 myoff = self.utcoffset()
1734 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
1735 base_compare = myoff == otoff 1863 base_compare = myoff == otoff
1736 1864
1737 if base_compare: 1865 if base_compare:
1738 return _cmp((self._year, self._month, self._day, 1866 return _cmp((self._year, self._month, self._day,
1739 self._hour, self._minute, self._second, 1867 self._hour, self._minute, self._second,
1740 self._microsecond), 1868 self._microsecond),
1741 (other._year, other._month, other._day, 1869 (other._year, other._month, other._day,
1742 other._hour, other._minute, other._second, 1870 other._hour, other._minute, other._second,
1743 other._microsecond)) 1871 other._microsecond))
1744 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
1792 myoff = self.utcoffset() 1920 myoff = self.utcoffset()
1793 otoff = other.utcoffset() 1921 otoff = other.utcoffset()
1794 if myoff == otoff: 1922 if myoff == otoff:
1795 return base 1923 return base
1796 if myoff is None or otoff is None: 1924 if myoff is None or otoff is None:
1797 raise TypeError("cannot mix naive and timezone-aware time") 1925 raise TypeError("cannot mix naive and timezone-aware time")
1798 return base + otoff - myoff 1926 return base + otoff - myoff
1799 1927
1800 def __hash__(self): 1928 def __hash__(self):
1801 if self._hashcode == -1: 1929 if self._hashcode == -1:
1802 tzoff = self.utcoffset() 1930 if self.fold:
1931 t = self.replace(fold=0)
1932 else:
1933 t = self
1934 tzoff = t.utcoffset()
1803 if tzoff is None: 1935 if tzoff is None:
1804 self._hashcode = hash(self._getstate()[0]) 1936 self._hashcode = hash(t._getstate()[0])
1805 else: 1937 else:
1806 days = _ymd2ord(self.year, self.month, self.day) 1938 days = _ymd2ord(self.year, self.month, self.day)
1807 seconds = self.hour * 3600 + self.minute * 60 + self.second 1939 seconds = self.hour * 3600 + self.minute * 60 + self.second
1808 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff) 1940 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1809 return self._hashcode 1941 return self._hashcode
1810 1942
1811 # Pickle support. 1943 # Pickle support.
1812 1944
1813 def _getstate(self): 1945 def _getstate(self, protocol=3):
1814 yhi, ylo = divmod(self._year, 256) 1946 yhi, ylo = divmod(self._year, 256)
1815 us2, us3 = divmod(self._microsecond, 256) 1947 us2, us3 = divmod(self._microsecond, 256)
1816 us1, us2 = divmod(us2, 256) 1948 us1, us2 = divmod(us2, 256)
1817 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,
1818 self._hour, self._minute, self._second, 1953 self._hour, self._minute, self._second,
1819 us1, us2, us3]) 1954 us1, us2, us3])
1820 if self._tzinfo is None: 1955 if self._tzinfo is None:
1821 return (basestate,) 1956 return (basestate,)
1822 else: 1957 else:
1823 return (basestate, self._tzinfo) 1958 return (basestate, self._tzinfo)
1824 1959
1825 def __setstate(self, string, tzinfo): 1960 def __setstate(self, string, tzinfo):
1826 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class): 1961 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1827 raise TypeError("bad tzinfo state arg") 1962 raise TypeError("bad tzinfo state arg")
1828 (yhi, ylo, self._month, self._day, self._hour, 1963 (yhi, ylo, m, self._day, self._hour,
1829 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
1830 self._year = yhi * 256 + ylo 1971 self._year = yhi * 256 + ylo
1831 self._microsecond = (((us1 << 8) | us2) << 8) | us3 1972 self._microsecond = (((us1 << 8) | us2) << 8) | us3
1832 self._tzinfo = tzinfo 1973 self._tzinfo = tzinfo
1833 1974
1834 def __reduce__(self): 1975 def __reduce_ex__(self, protocol):
1835 return (self.__class__, self._getstate()) 1976 return (self.__class__, self._getstate(protocol))
1836 1977
1837 1978
1838 datetime.min = datetime(1, 1, 1) 1979 datetime.min = datetime(1, 1, 1)
1839 datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999) 1980 datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1840 datetime.resolution = timedelta(microseconds=1) 1981 datetime.resolution = timedelta(microseconds=1)
1841 1982
1842 1983
1843 def _isoweek1monday(year): 1984 def _isoweek1monday(year):
1844 # 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
1845 # XXX This could be done more efficiently 1986 # XXX This could be done more efficiently
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
2176 _check_date_fields, _check_int_field, _check_time_fields, 2317 _check_date_fields, _check_int_field, _check_time_fields,
2177 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror, 2318 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2178 _date_class, _days_before_month, _days_before_year, _days_in_month, 2319 _date_class, _days_before_month, _days_before_year, _days_in_month,
2179 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd, 2320 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2180 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord) 2321 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
2181 # XXX Since import * above excludes names that start with _, 2322 # XXX Since import * above excludes names that start with _,
2182 # docstring does not get overwritten. In the future, it may be 2323 # docstring does not get overwritten. In the future, it may be
2183 # appropriate to maintain a single module level docstring and 2324 # appropriate to maintain a single module level docstring and
2184 # remove the following line. 2325 # remove the following line.
2185 from _datetime import __doc__ 2326 from _datetime import __doc__
LEFTRIGHT

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