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

Delta Between Two Patch Sets: Lib/datetime.py

Issue 15873: "datetime" cannot parse ISO 8601 dates and times
Left Patch Set: Created 4 years, 3 months ago
Right Patch Set: Created 3 years, 9 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 10
12 def _cmp(x, y): 11 def _cmp(x, y):
13 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
14 13
15 MINYEAR = 1 14 MINYEAR = 1
16 MAXYEAR = 9999 15 MAXYEAR = 9999
17 _MAXORDINAL = 3652059 # date.max.toordinal() 16 _MAXORDINAL = 3652059 # date.max.toordinal()
18 17
19 # Utility functions, adapted from Python's Demo/classes/Dates.py, which 18 # Utility functions, adapted from Python's Demo/classes/Dates.py, which
20 # 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
147 _MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun", 146 _MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
148 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 147 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
149 _DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] 148 _DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
150 149
151 150
152 def _build_struct_time(y, m, d, hh, mm, ss, dstflag): 151 def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
153 wday = (_ymd2ord(y, m, d) + 6) % 7 152 wday = (_ymd2ord(y, m, d) + 6) % 7
154 dnum = _days_before_month(y, m) + d 153 dnum = _days_before_month(y, m) + d
155 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))
156 155
157 def _format_time(hh, mm, ss, us): 156 def _format_time(hh, mm, ss, us, timespec='auto'):
158 # Skip trailing microseconds when us==0. 157 specs = {
159 result = "%02d:%02d:%02d" % (hh, mm, ss) 158 'hours': '{:02d}',
160 if us: 159 'minutes': '{:02d}:{:02d}',
161 result += ".%06d" % us 160 'seconds': '{:02d}:{:02d}:{:02d}',
162 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)
163 176
164 # Correctly substitute for %z and %Z escapes in strftime formats. 177 # Correctly substitute for %z and %Z escapes in strftime formats.
165 def _wrap_strftime(object, format, timetuple): 178 def _wrap_strftime(object, format, timetuple):
166 # Don't call utcoffset() or tzname() unless actually needed. 179 # Don't call utcoffset() or tzname() unless actually needed.
167 freplace = None # the string to use for %f 180 freplace = None # the string to use for %f
168 zreplace = None # the string to use for %z 181 zreplace = None # the string to use for %z
169 Zreplace = None # the string to use for %Z 182 Zreplace = None # the string to use for %Z
170 183
171 # Scan format for %z and %Z escapes, replacing as needed. 184 # Scan format for %z and %Z escapes, replacing as needed.
172 newformat = [] 185 newformat = []
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 # If offset is None, returns None. 244 # If offset is None, returns None.
232 # 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.
233 # 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.
234 def _check_utc_offset(name, offset): 247 def _check_utc_offset(name, offset):
235 assert name in ("utcoffset", "dst") 248 assert name in ("utcoffset", "dst")
236 if offset is None: 249 if offset is None:
237 return 250 return
238 if not isinstance(offset, timedelta): 251 if not isinstance(offset, timedelta):
239 raise TypeError("tzinfo.%s() must return None " 252 raise TypeError("tzinfo.%s() must return None "
240 "or timedelta, not '%s'" % (name, type(offset))) 253 "or timedelta, not '%s'" % (name, type(offset)))
241 if offset % timedelta(minutes=1) or offset.microseconds: 254 if offset.microseconds:
242 raise ValueError("tzinfo.%s() must return a whole number " 255 raise ValueError("tzinfo.%s() must return a whole number "
243 "of minutes, got %s" % (name, offset)) 256 "of seconds, got %s" % (name, offset))
244 if not -timedelta(1) < offset < timedelta(1): 257 if not -timedelta(1) < offset < timedelta(1):
245 raise ValueError("%s()=%s, must be must be strictly between " 258 raise ValueError("%s()=%s, must be strictly between "
246 "-timedelta(hours=24) and timedelta(hours=24)" % 259 "-timedelta(hours=24) and timedelta(hours=24)" %
247 (name, offset)) 260 (name, offset))
248 261
249 def _check_int_field(value): 262 def _check_int_field(value):
250 if isinstance(value, int): 263 if isinstance(value, int):
251 return value 264 return value
252 if not isinstance(value, float): 265 if not isinstance(value, float):
253 try: 266 try:
254 value = value.__int__() 267 value = value.__int__()
255 except AttributeError: 268 except AttributeError:
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 q, r = divmod(a, b) 323 q, r = divmod(a, b)
311 # 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.
312 # 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
313 # positive, 2 * r < b if b negative. 326 # positive, 2 * r < b if b negative.
314 r *= 2 327 r *= 2
315 greater_than_half = r > b if b > 0 else r < b 328 greater_than_half = r > b if b > 0 else r < b
316 if greater_than_half or r == b and q % 2 == 1: 329 if greater_than_half or r == b and q % 2 == 1:
317 q += 1 330 q += 1
318 331
319 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)
320 358
321 359
322 class timedelta: 360 class timedelta:
323 """Represent the difference between two datetime objects. 361 """Represent the difference between two datetime objects.
324 362
325 Supported operators: 363 Supported operators:
326 364
327 - add, subtract timedelta 365 - add, subtract timedelta
328 - unary plus, minus, abs 366 - unary plus, minus, abs
329 - compare to timedelta 367 - compare to timedelta
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 return (self._days, self._seconds, self._microseconds) 672 return (self._days, self._seconds, self._microseconds)
635 673
636 def __reduce__(self): 674 def __reduce__(self):
637 return (self.__class__, self._getstate()) 675 return (self.__class__, self._getstate())
638 676
639 timedelta.min = timedelta(-999999999) 677 timedelta.min = timedelta(-999999999)
640 timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59, 678 timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
641 microseconds=999999) 679 microseconds=999999)
642 timedelta.resolution = timedelta(microseconds=1) 680 timedelta.resolution = timedelta(microseconds=1)
643 681
644 _DATE_RE = re.compile(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})$', re.AS CII)
645
646 class date: 682 class date:
647 """Concrete date type. 683 """Concrete date type.
648 684
649 Constructors: 685 Constructors:
650 686
651 __new__() 687 __new__()
652 fromtimestamp() 688 fromtimestamp()
653 today() 689 today()
654 fromordinal() 690 fromordinal()
655 691
656 Operators: 692 Operators:
657 693
658 __repr__, __str__ 694 __repr__, __str__
659 __eq__, __le__, __lt__, __ge__, __gt__, __hash__ 695 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
660 __add__, __radd__, __sub__ (add/radd only with timedelta arg) 696 __add__, __radd__, __sub__ (add/radd only with timedelta arg)
661 697
662 Methods: 698 Methods:
663 699
664 timetuple() 700 timetuple()
665 toordinal() 701 toordinal()
666 weekday() 702 weekday()
667 isoweekday(), isocalendar(), isoformat() 703 isoweekday(), isocalendar(), isoformat()
668 ctime() 704 ctime()
669 strftime() 705 strftime()
670 706
671 Properties (readonly): 707 Properties (readonly):
672 year, month, day 708 year, month, day
673 """ 709 """
674 __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)
675 713
676 def __new__(cls, year, month=None, day=None): 714 def __new__(cls, year, month=None, day=None):
677 """Constructor. 715 """Constructor.
678 716
679 Arguments: 717 Arguments:
680 718
681 year, month, day (required, base 1) 719 year, month, day (required, base 1)
682 """ 720 """
683 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 \
684 1 <= year[2] <= 12: 722 1 <= year[2] <= 12:
(...skipping 19 matching lines...) Expand all
704 return cls(y, m, d) 742 return cls(y, m, d)
705 743
706 @classmethod 744 @classmethod
707 def today(cls): 745 def today(cls):
708 "Construct a date from time.time()." 746 "Construct a date from time.time()."
709 t = _time.time() 747 t = _time.time()
710 return cls.fromtimestamp(t) 748 return cls.fromtimestamp(t)
711 749
712 @classmethod 750 @classmethod
713 def fromordinal(cls, n): 751 def fromordinal(cls, n):
714 """Contruct a date from a proleptic Gregorian ordinal. 752 """Construct a date from a proleptic Gregorian ordinal.
715 753
716 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
717 non-zero in the result. 755 non-zero in the result.
718 """ 756 """
719 y, m, d = _ord2ymd(n) 757 y, m, d = _ord2ymd(n)
720 return cls(y, m, d) 758 return cls(y, m, d)
721 759
722 @classmethod 760 @classmethod
723 def fromisoformat(cls, date_string): 761 def fromisoformat(cls, date_string):
724 """Constructs a date from an RFC 3339 string, a strict subset of ISO 860 1 762 """Constructs a date from an RFC 3339 string, a strict subset of ISO 860 1
725 763
726 Raises ValueError in case of ill-formatted or invalid string. 764 Raises ValueError in case of ill-formatted or invalid string.
727 """ 765 """
728 m = _DATE_RE.match(date_string) 766 return _parse_isotime(cls, date_string)
729 if not m:
730 raise ValueError('invalid RFC 3339 date string: %r' % date_string)
731 kw = m.groupdict()
732 kw = {k: int(v) for k, v in kw.items()}
733 return cls(**kw)
734 767
735 # Conversions to string 768 # Conversions to string
736 769
737 def __repr__(self): 770 def __repr__(self):
738 """Convert to formal string, for repr(). 771 """Convert to formal string, for repr().
739 772
740 >>> dt = datetime(2010, 1, 1) 773 >>> dt = datetime(2010, 1, 1)
741 >>> repr(dt) 774 >>> repr(dt)
742 'datetime.datetime(2010, 1, 1, 0, 0)' 775 'datetime.datetime(2010, 1, 1, 0, 0)'
743 776
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
926 week1monday = _isoweek1monday(year) 959 week1monday = _isoweek1monday(year)
927 week, day = divmod(today - week1monday, 7) 960 week, day = divmod(today - week1monday, 7)
928 elif week >= 52: 961 elif week >= 52:
929 if today >= _isoweek1monday(year+1): 962 if today >= _isoweek1monday(year+1):
930 year += 1 963 year += 1
931 week = 0 964 week = 0
932 return year, week+1, day+1 965 return year, week+1, day+1
933 966
934 # Pickle support. 967 # Pickle support.
935 968
936 def _getstate(self): 969 def _getstate(self, protocol=3):
937 yhi, ylo = divmod(self._year, 256) 970 yhi, ylo = divmod(self._year, 256)
938 return bytes([yhi, ylo, self._month, self._day]), 971 return bytes([yhi, ylo, self._month, self._day]),
939 972
940 def __setstate(self, string): 973 def __setstate(self, string):
941 yhi, ylo, self._month, self._day = string 974 yhi, ylo, self._month, self._day = string
942 self._year = yhi * 256 + ylo 975 self._year = yhi * 256 + ylo
943 976
944 def __reduce__(self): 977 def __reduce_ex__(self, protocol):
945 return (self.__class__, self._getstate()) 978 return (self.__class__, self._getstate(protocol))
946 979
947 _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
948 981
949 date.min = date(1, 1, 1) 982 date.min = date(1, 1, 1)
950 date.max = date(9999, 12, 31) 983 date.max = date(9999, 12, 31)
951 date.resolution = timedelta(days=1) 984 date.resolution = timedelta(days=1)
985
952 986
953 class tzinfo: 987 class tzinfo:
954 """Abstract base class for time zone info classes. 988 """Abstract base class for time zone info classes.
955 989
956 Subclasses must override the name(), utcoffset() and dst() methods. 990 Subclasses must override the name(), utcoffset() and dst() methods.
957 """ 991 """
958 __slots__ = () 992 __slots__ = ()
959 993
960 def tzname(self, dt): 994 def tzname(self, dt):
961 "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
1013 state = getstate() 1047 state = getstate()
1014 else: 1048 else:
1015 state = getattr(self, "__dict__", None) or None 1049 state = getattr(self, "__dict__", None) or None
1016 if state is None: 1050 if state is None:
1017 return (self.__class__, args) 1051 return (self.__class__, args)
1018 else: 1052 else:
1019 return (self.__class__, args, state) 1053 return (self.__class__, args, state)
1020 1054
1021 _tzinfo_class = tzinfo 1055 _tzinfo_class = tzinfo
1022 1056
1023 _TIME_RE = re.compile(r'(?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2})'
1024 r'(?P<microsecond>\.\d*)?(?P<tzinfo>Z|([+-]\d{2}:\d{2}))?$' ,
1025 re.ASCII|re.IGNORECASE)
1026 1057
1027 class time: 1058 class time:
1028 """Time with time zone. 1059 """Time with time zone.
1029 1060
1030 Constructors: 1061 Constructors:
1031 1062
1032 __new__() 1063 __new__()
1033 1064
1034 Operators: 1065 Operators:
1035 1066
1036 __repr__, __str__ 1067 __repr__, __str__
1037 __eq__, __le__, __lt__, __ge__, __gt__, __hash__ 1068 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
1038 1069
1039 Methods: 1070 Methods:
1040 1071
1041 strftime() 1072 strftime()
1042 isoformat() 1073 isoformat()
1043 utcoffset() 1074 utcoffset()
1044 tzname() 1075 tzname()
1045 dst() 1076 dst()
1046 1077
1047 Properties (readonly): 1078 Properties (readonly):
1048 hour, minute, second, microsecond, tzinfo 1079 hour, minute, second, microsecond, tzinfo, fold
1049 """ 1080 """
1050 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hash code' 1081 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hash code', '_fold'
1051 1082
1052 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):
1053 """Constructor. 1089 """Constructor.
1054 1090
1055 Arguments: 1091 Arguments:
1056 1092
1057 hour, minute (required) 1093 hour, minute (required)
1058 second, microsecond (default to zero) 1094 second, microsecond (default to zero)
1059 tzinfo (default to None) 1095 tzinfo (default to None)
1096 fold (keyword only, default to True)
1060 """ 1097 """
1061 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:
1062 # Pickle support 1099 # Pickle support
1063 self = object.__new__(cls) 1100 self = object.__new__(cls)
1064 self.__setstate(hour, minute or None) 1101 self.__setstate(hour, minute or None)
1065 self._hashcode = -1 1102 self._hashcode = -1
1066 return self 1103 return self
1067 hour, minute, second, microsecond = _check_time_fields( 1104 hour, minute, second, microsecond = _check_time_fields(
1068 hour, minute, second, microsecond) 1105 hour, minute, second, microsecond)
1069 _check_tzinfo_arg(tzinfo) 1106 _check_tzinfo_arg(tzinfo)
1070 self = object.__new__(cls) 1107 self = object.__new__(cls)
1071 self._hour = hour 1108 self._hour = hour
1072 self._minute = minute 1109 self._minute = minute
1073 self._second = second 1110 self._second = second
1074 self._microsecond = microsecond 1111 self._microsecond = microsecond
1075 self._tzinfo = tzinfo 1112 self._tzinfo = tzinfo
1076 self._hashcode = -1 1113 self._hashcode = -1
1114 self._fold = fold
1077 return self 1115 return self
1078
1079 @staticmethod
1080 def _parse_isotime(reg, isostring, class_name):
1081 match = reg.match(isostring)
1082 if not match:
1083 raise ValueError('invalid RFC 3339 %s string: %r' % (class_name, iso string))
1084 kw = match.groupdict()
1085 tzinfo = kw.pop('tzinfo', None)
1086 if tzinfo == 'Z' or tzinfo == 'z':
1087 tzinfo = timezone.utc
1088 elif tzinfo is not None:
1089 offset_hours, _, offset_mins = tzinfo[1:].partition(':')
1090 offset = timedelta(hours=int(offset_hours), minutes=int(offset_mins) )
1091 if tzinfo[0] == '-':
1092 offset = -offset
1093 tzinfo = timezone(offset)
1094 us = kw.pop('microsecond', None)
1095 kw = {k: int(v) for k, v in kw.items() if v is not None}
1096 if us:
1097 us = round(float(us), 6)
1098 kw['microsecond'] = int(us * 1e6)
1099 kw['tzinfo'] = tzinfo
1100 return kw
1101 1116
1102 @classmethod 1117 @classmethod
1103 def fromisoformat(cls, time_string): 1118 def fromisoformat(cls, time_string):
1104 """Constructs a time from an RFC 3339 string, a strict subset of ISO 860 1 1119 """Constructs a time from an RFC 3339 string, a strict subset of ISO 860 1
1105 1120
1106 Microseconds are rounded to 6 digits. 1121 Microseconds are rounded to 6 digits.
1107 Raises ValueError in case of ill-formatted or invalid string. 1122 Raises ValueError in case of ill-formatted or invalid string.
1108 """ 1123 """
1109 kw = cls._parse_isotime(_TIME_RE, time_string, cls.__name__) 1124 return _parse_isotime(cls, time_string)
1110 return cls(**kw)
1111
1112 1125
1113 # Read-only field accessors 1126 # Read-only field accessors
1114 @property 1127 @property
1115 def hour(self): 1128 def hour(self):
1116 """hour (0-23)""" 1129 """hour (0-23)"""
1117 return self._hour 1130 return self._hour
1118 1131
1119 @property 1132 @property
1120 def minute(self): 1133 def minute(self):
1121 """minute (0-59)""" 1134 """minute (0-59)"""
1122 return self._minute 1135 return self._minute
1123 1136
1124 @property 1137 @property
1125 def second(self): 1138 def second(self):
1126 """second (0-59)""" 1139 """second (0-59)"""
1127 return self._second 1140 return self._second
1128 1141
1129 @property 1142 @property
1130 def microsecond(self): 1143 def microsecond(self):
1131 """microsecond (0-999999)""" 1144 """microsecond (0-999999)"""
1132 return self._microsecond 1145 return self._microsecond
1133 1146
1134 @property 1147 @property
1135 def tzinfo(self): 1148 def tzinfo(self):
1136 """timezone info object""" 1149 """timezone info object"""
1137 return self._tzinfo 1150 return self._tzinfo
1151
1152 @property
1153 def fold(self):
1154 return self._fold
1138 1155
1139 # Standard conversions, __hash__ (and helpers) 1156 # Standard conversions, __hash__ (and helpers)
1140 1157
1141 # Comparisons of time objects with other. 1158 # Comparisons of time objects with other.
1142 1159
1143 def __eq__(self, other): 1160 def __eq__(self, other):
1144 if isinstance(other, time): 1161 if isinstance(other, time):
1145 return self._cmp(other, allow_mixed=True) == 0 1162 return self._cmp(other, allow_mixed=True) == 0
1146 else: 1163 else:
1147 return False 1164 return False
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1194 else: 1211 else:
1195 raise TypeError("cannot compare naive and aware times") 1212 raise TypeError("cannot compare naive and aware times")
1196 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1) 1213 myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)
1197 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1) 1214 othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)
1198 return _cmp((myhhmm, self._second, self._microsecond), 1215 return _cmp((myhhmm, self._second, self._microsecond),
1199 (othhmm, other._second, other._microsecond)) 1216 (othhmm, other._second, other._microsecond))
1200 1217
1201 def __hash__(self): 1218 def __hash__(self):
1202 """Hash.""" 1219 """Hash."""
1203 if self._hashcode == -1: 1220 if self._hashcode == -1:
1204 tzoff = self.utcoffset() 1221 if self.fold:
1222 t = self.replace(fold=0)
1223 else:
1224 t = self
1225 tzoff = t.utcoffset()
1205 if not tzoff: # zero or None 1226 if not tzoff: # zero or None
1206 self._hashcode = hash(self._getstate()[0]) 1227 self._hashcode = hash(t._getstate()[0])
1207 else: 1228 else:
1208 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff, 1229 h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
1209 timedelta(hours=1)) 1230 timedelta(hours=1))
1210 assert not m % timedelta(minutes=1), "whole minute" 1231 assert not m % timedelta(minutes=1), "whole minute"
1211 m //= timedelta(minutes=1) 1232 m //= timedelta(minutes=1)
1212 if 0 <= h < 24: 1233 if 0 <= h < 24:
1213 self._hashcode = hash(time(h, m, self.second, self.microseco nd)) 1234 self._hashcode = hash(time(h, m, self.second, self.microseco nd))
1214 else: 1235 else:
1215 self._hashcode = hash((h, m, self.second, self.microsecond)) 1236 self._hashcode = hash((h, m, self.second, self.microsecond))
1216 return self._hashcode 1237 return self._hashcode
1217 1238
1218 # Conversion to string 1239 # Conversion to string
1219 1240
1220 def _tzstr(self, sep=":"): 1241 def _tzstr(self, sep=":"):
1221 """Return formatted timezone offset (+xx:xx) or None.""" 1242 """Return formatted timezone offset (+xx:xx) or None."""
1222 off = self.utcoffset() 1243 off = self.utcoffset()
1223 if off is not None: 1244 if off is not None:
1224 if off.days < 0: 1245 if off.days < 0:
1225 sign = "-" 1246 sign = "-"
1226 off = -off 1247 off = -off
1227 else: 1248 else:
1228 sign = "+" 1249 sign = "+"
1229 hh, mm = divmod(off, timedelta(hours=1)) 1250 hh, mm = divmod(off, timedelta(hours=1))
1230 assert not mm % timedelta(minutes=1), "whole minute" 1251 mm, ss = divmod(mm, timedelta(minutes=1))
1231 mm //= timedelta(minutes=1)
1232 assert 0 <= hh < 24 1252 assert 0 <= hh < 24
1233 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
1234 return off 1256 return off
1235 1257
1236 def __repr__(self): 1258 def __repr__(self):
1237 """Convert to formal string, for repr().""" 1259 """Convert to formal string, for repr()."""
1238 if self._microsecond != 0: 1260 if self._microsecond != 0:
1239 s = ", %d, %d" % (self._second, self._microsecond) 1261 s = ", %d, %d" % (self._second, self._microsecond)
1240 elif self._second != 0: 1262 elif self._second != 0:
1241 s = ", %d" % self._second 1263 s = ", %d" % self._second
1242 else: 1264 else:
1243 s = "" 1265 s = ""
1244 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__, 1266 s= "%s.%s(%d, %d%s)" % (self.__class__.__module__,
1245 self.__class__.__qualname__, 1267 self.__class__.__qualname__,
1246 self._hour, self._minute, s) 1268 self._hour, self._minute, s)
1247 if self._tzinfo is not None: 1269 if self._tzinfo is not None:
1248 assert s[-1:] == ")" 1270 assert s[-1:] == ")"
1249 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)"
1250 return s 1275 return s
1251 1276
1252 def isoformat(self): 1277 def isoformat(self, timespec='auto'):
1253 """Return the time formatted according to ISO. 1278 """Return the time formatted according to ISO.
1254 1279
1255 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
1256 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.
1257 """ 1285 """
1258 s = _format_time(self._hour, self._minute, self._second, 1286 s = _format_time(self._hour, self._minute, self._second,
1259 self._microsecond) 1287 self._microsecond, timespec)
1260 tz = self._tzstr() 1288 tz = self._tzstr()
1261 if tz: 1289 if tz:
1262 s += tz 1290 s += tz
1263 return s 1291 return s
1264 1292
1265 __str__ = isoformat 1293 __str__ = isoformat
1266 1294
1267 def strftime(self, fmt): 1295 def strftime(self, fmt):
1268 """Format using strftime(). The date part of the timestamp passed 1296 """Format using strftime(). The date part of the timestamp passed
1269 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
1315 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
1316 info. 1344 info.
1317 """ 1345 """
1318 if self._tzinfo is None: 1346 if self._tzinfo is None:
1319 return None 1347 return None
1320 offset = self._tzinfo.dst(None) 1348 offset = self._tzinfo.dst(None)
1321 _check_utc_offset("dst", offset) 1349 _check_utc_offset("dst", offset)
1322 return offset 1350 return offset
1323 1351
1324 def replace(self, hour=None, minute=None, second=None, microsecond=None, 1352 def replace(self, hour=None, minute=None, second=None, microsecond=None,
1325 tzinfo=True): 1353 tzinfo=True, *, fold=None):
1326 """Return a new time with new values for the specified fields.""" 1354 """Return a new time with new values for the specified fields."""
1327 if hour is None: 1355 if hour is None:
1328 hour = self.hour 1356 hour = self.hour
1329 if minute is None: 1357 if minute is None:
1330 minute = self.minute 1358 minute = self.minute
1331 if second is None: 1359 if second is None:
1332 second = self.second 1360 second = self.second
1333 if microsecond is None: 1361 if microsecond is None:
1334 microsecond = self.microsecond 1362 microsecond = self.microsecond
1335 if tzinfo is True: 1363 if tzinfo is True:
1336 tzinfo = self.tzinfo 1364 tzinfo = self.tzinfo
1337 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)
1338 1368
1339 # Pickle support. 1369 # Pickle support.
1340 1370
1341 def _getstate(self): 1371 def _getstate(self, protocol=3):
1342 us2, us3 = divmod(self._microsecond, 256) 1372 us2, us3 = divmod(self._microsecond, 256)
1343 us1, us2 = divmod(us2, 256) 1373 us1, us2 = divmod(us2, 256)
1344 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,
1345 us1, us2, us3]) 1378 us1, us2, us3])
1346 if self._tzinfo is None: 1379 if self._tzinfo is None:
1347 return (basestate,) 1380 return (basestate,)
1348 else: 1381 else:
1349 return (basestate, self._tzinfo) 1382 return (basestate, self._tzinfo)
1350 1383
1351 def __setstate(self, string, tzinfo): 1384 def __setstate(self, string, tzinfo):
1352 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class): 1385 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1353 raise TypeError("bad tzinfo state arg") 1386 raise TypeError("bad tzinfo state arg")
1354 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
1355 self._microsecond = (((us1 << 8) | us2) << 8) | us3 1394 self._microsecond = (((us1 << 8) | us2) << 8) | us3
1356 self._tzinfo = tzinfo 1395 self._tzinfo = tzinfo
1357 1396
1358 def __reduce__(self): 1397 def __reduce_ex__(self, protocol):
1359 return (time, self._getstate()) 1398 return (time, self._getstate(protocol))
1360 1399
1361 _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
1362 1401
1363 time.min = time(0, 0, 0) 1402 time.min = time(0, 0, 0)
1364 time.max = time(23, 59, 59, 999999) 1403 time.max = time(23, 59, 59, 999999)
1365 time.resolution = timedelta(microseconds=1) 1404 time.resolution = timedelta(microseconds=1)
1366
1367 _DATETIME_RE = re.compile(_DATE_RE.pattern[:-1] + r'[T ]' + _TIME_RE.pattern,
1368 re.ASCII|re.IGNORECASE)
1369 1405
1370 class datetime(date): 1406 class datetime(date):
1371 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo] ]]]]) 1407 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo] ]]]])
1372 1408
1373 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
1374 instance of a tzinfo subclass. The remaining arguments may be ints. 1410 instance of a tzinfo subclass. The remaining arguments may be ints.
1375 """ 1411 """
1376 __slots__ = date.__slots__ + time.__slots__ 1412 __slots__ = date.__slots__ + time.__slots__
1377 1413
1414 _isore = re.compile(date._isore.pattern[:-1] + r'[T ]' +
1415 time._isore.pattern, re.ASCII|re.IGNORECASE)
1416
1378 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,
1379 microsecond=0, tzinfo=None): 1418 microsecond=0, tzinfo=None, *, fold=0):
1380 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:
1381 # Pickle support 1420 # Pickle support
1382 self = object.__new__(cls) 1421 self = object.__new__(cls)
1383 self.__setstate(year, month) 1422 self.__setstate(year, month)
1384 self._hashcode = -1 1423 self._hashcode = -1
1385 return self 1424 return self
1386 year, month, day = _check_date_fields(year, month, day) 1425 year, month, day = _check_date_fields(year, month, day)
1387 hour, minute, second, microsecond = _check_time_fields( 1426 hour, minute, second, microsecond = _check_time_fields(
1388 hour, minute, second, microsecond) 1427 hour, minute, second, microsecond)
1389 _check_tzinfo_arg(tzinfo) 1428 _check_tzinfo_arg(tzinfo)
1390 self = object.__new__(cls) 1429 self = object.__new__(cls)
1391 self._year = year 1430 self._year = year
1392 self._month = month 1431 self._month = month
1393 self._day = day 1432 self._day = day
1394 self._hour = hour 1433 self._hour = hour
1395 self._minute = minute 1434 self._minute = minute
1396 self._second = second 1435 self._second = second
1397 self._microsecond = microsecond 1436 self._microsecond = microsecond
1398 self._tzinfo = tzinfo 1437 self._tzinfo = tzinfo
1399 self._hashcode = -1 1438 self._hashcode = -1
1439 self._fold = fold
1400 return self 1440 return self
1401 1441
1402 # Read-only field accessors 1442 # Read-only field accessors
1403 @property 1443 @property
1404 def hour(self): 1444 def hour(self):
1405 """hour (0-23)""" 1445 """hour (0-23)"""
1406 return self._hour 1446 return self._hour
1407 1447
1408 @property 1448 @property
1409 def minute(self): 1449 def minute(self):
1410 """minute (0-59)""" 1450 """minute (0-59)"""
1411 return self._minute 1451 return self._minute
1412 1452
1413 @property 1453 @property
1414 def second(self): 1454 def second(self):
1415 """second (0-59)""" 1455 """second (0-59)"""
1416 return self._second 1456 return self._second
1417 1457
1418 @property 1458 @property
1419 def microsecond(self): 1459 def microsecond(self):
1420 """microsecond (0-999999)""" 1460 """microsecond (0-999999)"""
1421 return self._microsecond 1461 return self._microsecond
1422 1462
1423 @property 1463 @property
1424 def tzinfo(self): 1464 def tzinfo(self):
1425 """timezone info object""" 1465 """timezone info object"""
1426 return self._tzinfo 1466 return self._tzinfo
1467
1468 @property
1469 def fold(self):
1470 return self._fold
1427 1471
1428 @classmethod 1472 @classmethod
1429 def _fromtimestamp(cls, t, utc, tz): 1473 def _fromtimestamp(cls, t, utc, tz):
1430 """Construct a datetime from a POSIX timestamp (like time.time()). 1474 """Construct a datetime from a POSIX timestamp (like time.time()).
1431 1475
1432 A timezone info object may be passed in as well. 1476 A timezone info object may be passed in as well.
1433 """ 1477 """
1434 frac, t = _math.modf(t) 1478 frac, t = _math.modf(t)
1435 us = round(frac * 1e6) 1479 us = round(frac * 1e6)
1436 if us >= 1000000: 1480 if us >= 1000000:
1437 t += 1 1481 t += 1
1438 us -= 1000000 1482 us -= 1000000
1439 elif us < 0: 1483 elif us < 0:
1440 t -= 1 1484 t -= 1
1441 us += 1000000 1485 us += 1000000
1442 1486
1443 converter = _time.gmtime if utc else _time.localtime 1487 converter = _time.gmtime if utc else _time.localtime
1444 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) 1488 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
1445 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
1446 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
1447 1507
1448 @classmethod 1508 @classmethod
1449 def fromtimestamp(cls, t, tz=None): 1509 def fromtimestamp(cls, t, tz=None):
1450 """Construct a datetime from a POSIX timestamp (like time.time()). 1510 """Construct a datetime from a POSIX timestamp (like time.time()).
1451 1511
1452 A timezone info object may be passed in as well. 1512 A timezone info object may be passed in as well.
1453 """ 1513 """
1454 _check_tzinfo_arg(tz) 1514 _check_tzinfo_arg(tz)
1455 1515
1456 result = cls._fromtimestamp(t, tz is not None, tz) 1516 return cls._fromtimestamp(t, tz is not None, tz)
1457 if tz is not None:
1458 result = tz.fromutc(result)
1459 return result
1460 1517
1461 @classmethod 1518 @classmethod
1462 def utcfromtimestamp(cls, t): 1519 def utcfromtimestamp(cls, t):
1463 """Construct a naive UTC datetime from a POSIX timestamp.""" 1520 """Construct a naive UTC datetime from a POSIX timestamp."""
1464 return cls._fromtimestamp(t, True, None) 1521 return cls._fromtimestamp(t, True, None)
1465 1522
1466 @classmethod 1523 @classmethod
1467 def now(cls, tz=None): 1524 def now(cls, tz=None):
1468 "Construct a datetime from time.time() and optional time zone info." 1525 "Construct a datetime from time.time() and optional time zone info."
1469 t = _time.time() 1526 t = _time.time()
1470 return cls.fromtimestamp(t, tz) 1527 return cls.fromtimestamp(t, tz)
1471 1528
1472 @classmethod 1529 @classmethod
1473 def utcnow(cls): 1530 def utcnow(cls):
1474 "Construct a UTC datetime from time.time()." 1531 "Construct a UTC datetime from time.time()."
1475 t = _time.time() 1532 t = _time.time()
1476 return cls.utcfromtimestamp(t) 1533 return cls.utcfromtimestamp(t)
1477 1534
1478 @classmethod 1535 @classmethod
1479 def combine(cls, date, time): 1536 def combine(cls, date, time, tzinfo=True):
1480 "Construct a datetime from a given date and a given time." 1537 "Construct a datetime from a given date and a given time."
1481 if not isinstance(date, _date_class): 1538 if not isinstance(date, _date_class):
1482 raise TypeError("date argument must be a date instance") 1539 raise TypeError("date argument must be a date instance")
1483 if not isinstance(time, _time_class): 1540 if not isinstance(time, _time_class):
1484 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
1485 return cls(date.year, date.month, date.day, 1544 return cls(date.year, date.month, date.day,
1486 time.hour, time.minute, time.second, time.microsecond, 1545 time.hour, time.minute, time.second, time.microsecond,
1487 time.tzinfo) 1546 tzinfo, fold=time.fold)
1488
1489 @classmethod
1490 def fromisoformat(cls, datetime_string):
1491 """Constructs a datetime from an RFC 3339 string, a strict subset of ISO 8601
1492
1493 Microseconds are rounded to 6 digits.
1494 Raises ValueError if string is ill formatted or invalid
1495 """
1496 kw = time._parse_isotime(_DATETIME_RE, datetime_string, cls.__name__)
1497 return cls(**kw)
1498 1547
1499 def timetuple(self): 1548 def timetuple(self):
1500 "Return local time tuple compatible with time.localtime()." 1549 "Return local time tuple compatible with time.localtime()."
1501 dst = self.dst() 1550 dst = self.dst()
1502 if dst is None: 1551 if dst is None:
1503 dst = -1 1552 dst = -1
1504 elif dst: 1553 elif dst:
1505 dst = 1 1554 dst = 1
1506 else: 1555 else:
1507 dst = 0 1556 dst = 0
1508 return _build_struct_time(self.year, self.month, self.day, 1557 return _build_struct_time(self.year, self.month, self.day,
1509 self.hour, self.minute, self.second, 1558 self.hour, self.minute, self.second,
1510 dst) 1559 dst)
1511 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
1512 def timestamp(self): 1596 def timestamp(self):
1513 "Return POSIX timestamp as float" 1597 "Return POSIX timestamp as float"
1514 if self._tzinfo is None: 1598 if self._tzinfo is None:
1515 return _time.mktime((self.year, self.month, self.day, 1599 s = self._mktime()
1516 self.hour, self.minute, self.second, 1600 return s + self.microsecond / 1e6
1517 -1, -1, -1)) + self.microsecond / 1e6
1518 else: 1601 else:
1519 return (self - _EPOCH).total_seconds() 1602 return (self - _EPOCH).total_seconds()
1520 1603
1521 def utctimetuple(self): 1604 def utctimetuple(self):
1522 "Return UTC time tuple compatible with time.gmtime()." 1605 "Return UTC time tuple compatible with time.gmtime()."
1523 offset = self.utcoffset() 1606 offset = self.utcoffset()
1524 if offset: 1607 if offset:
1525 self -= offset 1608 self -= offset
1526 y, m, d = self.year, self.month, self.day 1609 y, m, d = self.year, self.month, self.day
1527 hh, mm, ss = self.hour, self.minute, self.second 1610 hh, mm, ss = self.hour, self.minute, self.second
1528 return _build_struct_time(y, m, d, hh, mm, ss, 0) 1611 return _build_struct_time(y, m, d, hh, mm, ss, 0)
1529 1612
1530 def date(self): 1613 def date(self):
1531 "Return the date part." 1614 "Return the date part."
1532 return date(self._year, self._month, self._day) 1615 return date(self._year, self._month, self._day)
1533 1616
1534 def time(self): 1617 def time(self):
1535 "Return the time part, with tzinfo None." 1618 "Return the time part, with tzinfo None."
1536 return time(self.hour, self.minute, self.second, self.microsecond) 1619 return time(self.hour, self.minute, self.second, self.microsecond, fold= self.fold)
1537 1620
1538 def timetz(self): 1621 def timetz(self):
1539 "Return the time part, with same tzinfo." 1622 "Return the time part, with same tzinfo."
1540 return time(self.hour, self.minute, self.second, self.microsecond, 1623 return time(self.hour, self.minute, self.second, self.microsecond,
1541 self._tzinfo) 1624 self._tzinfo, fold=self.fold)
1542 1625
1543 def replace(self, year=None, month=None, day=None, hour=None, 1626 def replace(self, year=None, month=None, day=None, hour=None,
1544 minute=None, second=None, microsecond=None, tzinfo=True): 1627 minute=None, second=None, microsecond=None, tzinfo=True,
1628 *, fold=None):
1545 """Return a new datetime with new values for the specified fields.""" 1629 """Return a new datetime with new values for the specified fields."""
1546 if year is None: 1630 if year is None:
1547 year = self.year 1631 year = self.year
1548 if month is None: 1632 if month is None:
1549 month = self.month 1633 month = self.month
1550 if day is None: 1634 if day is None:
1551 day = self.day 1635 day = self.day
1552 if hour is None: 1636 if hour is None:
1553 hour = self.hour 1637 hour = self.hour
1554 if minute is None: 1638 if minute is None:
1555 minute = self.minute 1639 minute = self.minute
1556 if second is None: 1640 if second is None:
1557 second = self.second 1641 second = self.second
1558 if microsecond is None: 1642 if microsecond is None:
1559 microsecond = self.microsecond 1643 microsecond = self.microsecond
1560 if tzinfo is True: 1644 if tzinfo is True:
1561 tzinfo = self.tzinfo 1645 tzinfo = self.tzinfo
1562 return datetime(year, month, day, hour, minute, second, microsecond, 1646 if fold is None:
1563 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
1564 1669
1565 def astimezone(self, tz=None): 1670 def astimezone(self, tz=None):
1566 if tz is None: 1671 if tz is None:
1567 if self.tzinfo is None: 1672 tz = self._local_timezone()
1568 raise ValueError("astimezone() requires an aware datetime")
1569 ts = (self - _EPOCH) // timedelta(seconds=1)
1570 localtm = _time.localtime(ts)
1571 local = datetime(*localtm[:6])
1572 try:
1573 # Extract TZ data if available
1574 gmtoff = localtm.tm_gmtoff
1575 zone = localtm.tm_zone
1576 except AttributeError:
1577 # Compute UTC offset and compare with the value implied
1578 # by tm_isdst. If the values match, use the zone name
1579 # implied by tm_isdst.
1580 delta = local - datetime(*_time.gmtime(ts)[:6])
1581 dst = _time.daylight and localtm.tm_isdst > 0
1582 gmtoff = -(_time.altzone if dst else _time.timezone)
1583 if delta == timedelta(seconds=gmtoff):
1584 tz = timezone(delta, _time.tzname[dst])
1585 else:
1586 tz = timezone(delta)
1587 else:
1588 tz = timezone(timedelta(seconds=gmtoff), zone)
1589
1590 elif not isinstance(tz, tzinfo): 1673 elif not isinstance(tz, tzinfo):
1591 raise TypeError("tz argument must be an instance of tzinfo") 1674 raise TypeError("tz argument must be an instance of tzinfo")
1592 1675
1593 mytz = self.tzinfo 1676 mytz = self.tzinfo
1594 if mytz is None: 1677 if mytz is None:
1595 raise ValueError("astimezone() requires an aware datetime") 1678 mytz = self._local_timezone()
1596 1679
1597 if tz is mytz: 1680 if tz is mytz:
1598 return self 1681 return self
1599 1682
1600 # Convert self to UTC, and attach the new time zone object. 1683 # Convert self to UTC, and attach the new time zone object.
1601 myoffset = self.utcoffset() 1684 myoffset = mytz.utcoffset(self)
1602 if myoffset is None: 1685 if myoffset is None:
1603 raise ValueError("astimezone() requires an aware datetime") 1686 raise ValueError("astimezone() requires an aware datetime")
1604 utc = (self - myoffset).replace(tzinfo=tz) 1687 utc = (self - myoffset).replace(tzinfo=tz)
1605 1688
1606 # Convert from UTC to tz's local time. 1689 # Convert from UTC to tz's local time.
1607 return tz.fromutc(utc) 1690 return tz.fromutc(utc)
1608 1691
1609 # Ways to produce a string. 1692 # Ways to produce a string.
1610 1693
1611 def ctime(self): 1694 def ctime(self):
1612 "Return ctime() style string." 1695 "Return ctime() style string."
1613 weekday = self.toordinal() % 7 or 7 1696 weekday = self.toordinal() % 7 or 7
1614 return "%s %s %2d %02d:%02d:%02d %04d" % ( 1697 return "%s %s %2d %02d:%02d:%02d %04d" % (
1615 _DAYNAMES[weekday], 1698 _DAYNAMES[weekday],
1616 _MONTHNAMES[self._month], 1699 _MONTHNAMES[self._month],
1617 self._day, 1700 self._day,
1618 self._hour, self._minute, self._second, 1701 self._hour, self._minute, self._second,
1619 self._year) 1702 self._year)
1620 1703
1621 def isoformat(self, sep='T'): 1704 def isoformat(self, sep='T', timespec='auto'):
1622 """Return the time formatted according to ISO. 1705 """Return the time formatted according to ISO.
1623 1706
1624 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'.
1625 self.microsecond == 0. 1708 By default, the fractional part is omitted if self.microsecond == 0.
1626 1709
1627 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
1628 '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'.
1629 1712
1630 Optional argument sep specifies the separator between date and 1713 Optional argument sep specifies the separator between date and
1631 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.
1632 """ 1718 """
1633 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) +
1634 _format_time(self._hour, self._minute, self._second, 1720 _format_time(self._hour, self._minute, self._second,
1635 self._microsecond)) 1721 self._microsecond, timespec))
1722
1636 off = self.utcoffset() 1723 off = self.utcoffset()
1637 if off is not None: 1724 if off is not None:
1638 if off.days < 0: 1725 if off.days < 0:
1639 sign = "-" 1726 sign = "-"
1640 off = -off 1727 off = -off
1641 else: 1728 else:
1642 sign = "+" 1729 sign = "+"
1643 hh, mm = divmod(off, timedelta(hours=1)) 1730 hh, mm = divmod(off, timedelta(hours=1))
1644 assert not mm % timedelta(minutes=1), "whole minute" 1731 mm, ss = divmod(mm, timedelta(minutes=1))
1645 mm //= timedelta(minutes=1)
1646 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
1647 return s 1736 return s
1648 1737
1649 def __repr__(self): 1738 def __repr__(self):
1650 """Convert to formal string, for repr().""" 1739 """Convert to formal string, for repr()."""
1651 L = [self._year, self._month, self._day, # These are never zero 1740 L = [self._year, self._month, self._day, # These are never zero
1652 self._hour, self._minute, self._second, self._microsecond] 1741 self._hour, self._minute, self._second, self._microsecond]
1653 if L[-1] == 0: 1742 if L[-1] == 0:
1654 del L[-1] 1743 del L[-1]
1655 if L[-1] == 0: 1744 if L[-1] == 0:
1656 del L[-1] 1745 del L[-1]
1657 s = "%s.%s(%s)" % (self.__class__.__module__, 1746 s = "%s.%s(%s)" % (self.__class__.__module__,
1658 self.__class__.__qualname__, 1747 self.__class__.__qualname__,
1659 ", ".join(map(str, L))) 1748 ", ".join(map(str, L)))
1660 if self._tzinfo is not None: 1749 if self._tzinfo is not None:
1661 assert s[-1:] == ")" 1750 assert s[-1:] == ")"
1662 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)"
1663 return s 1755 return s
1664 1756
1665 def __str__(self): 1757 def __str__(self):
1666 "Convert to string, for str()." 1758 "Convert to string, for str()."
1667 return self.isoformat(sep=' ') 1759 return self.isoformat(sep=' ')
1668 1760
1669 @classmethod 1761 @classmethod
1670 def strptime(cls, date_string, format): 1762 def strptime(cls, date_string, format):
1671 'string, format -> new datetime parsed from a string (like time.strptime ()).' 1763 'string, format -> new datetime parsed from a string (like time.strptime ()).'
1672 import _strptime 1764 import _strptime
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
1755 assert isinstance(other, datetime) 1847 assert isinstance(other, datetime)
1756 mytz = self._tzinfo 1848 mytz = self._tzinfo
1757 ottz = other._tzinfo 1849 ottz = other._tzinfo
1758 myoff = otoff = None 1850 myoff = otoff = None
1759 1851
1760 if mytz is ottz: 1852 if mytz is ottz:
1761 base_compare = True 1853 base_compare = True
1762 else: 1854 else:
1763 myoff = self.utcoffset() 1855 myoff = self.utcoffset()
1764 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
1765 base_compare = myoff == otoff 1863 base_compare = myoff == otoff
1766 1864
1767 if base_compare: 1865 if base_compare:
1768 return _cmp((self._year, self._month, self._day, 1866 return _cmp((self._year, self._month, self._day,
1769 self._hour, self._minute, self._second, 1867 self._hour, self._minute, self._second,
1770 self._microsecond), 1868 self._microsecond),
1771 (other._year, other._month, other._day, 1869 (other._year, other._month, other._day,
1772 other._hour, other._minute, other._second, 1870 other._hour, other._minute, other._second,
1773 other._microsecond)) 1871 other._microsecond))
1774 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
1822 myoff = self.utcoffset() 1920 myoff = self.utcoffset()
1823 otoff = other.utcoffset() 1921 otoff = other.utcoffset()
1824 if myoff == otoff: 1922 if myoff == otoff:
1825 return base 1923 return base
1826 if myoff is None or otoff is None: 1924 if myoff is None or otoff is None:
1827 raise TypeError("cannot mix naive and timezone-aware time") 1925 raise TypeError("cannot mix naive and timezone-aware time")
1828 return base + otoff - myoff 1926 return base + otoff - myoff
1829 1927
1830 def __hash__(self): 1928 def __hash__(self):
1831 if self._hashcode == -1: 1929 if self._hashcode == -1:
1832 tzoff = self.utcoffset() 1930 if self.fold:
1931 t = self.replace(fold=0)
1932 else:
1933 t = self
1934 tzoff = t.utcoffset()
1833 if tzoff is None: 1935 if tzoff is None:
1834 self._hashcode = hash(self._getstate()[0]) 1936 self._hashcode = hash(t._getstate()[0])
1835 else: 1937 else:
1836 days = _ymd2ord(self.year, self.month, self.day) 1938 days = _ymd2ord(self.year, self.month, self.day)
1837 seconds = self.hour * 3600 + self.minute * 60 + self.second 1939 seconds = self.hour * 3600 + self.minute * 60 + self.second
1838 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff) 1940 self._hashcode = hash(timedelta(days, seconds, self.microsecond) - tzoff)
1839 return self._hashcode 1941 return self._hashcode
1840 1942
1841 # Pickle support. 1943 # Pickle support.
1842 1944
1843 def _getstate(self): 1945 def _getstate(self, protocol=3):
1844 yhi, ylo = divmod(self._year, 256) 1946 yhi, ylo = divmod(self._year, 256)
1845 us2, us3 = divmod(self._microsecond, 256) 1947 us2, us3 = divmod(self._microsecond, 256)
1846 us1, us2 = divmod(us2, 256) 1948 us1, us2 = divmod(us2, 256)
1847 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,
1848 self._hour, self._minute, self._second, 1953 self._hour, self._minute, self._second,
1849 us1, us2, us3]) 1954 us1, us2, us3])
1850 if self._tzinfo is None: 1955 if self._tzinfo is None:
1851 return (basestate,) 1956 return (basestate,)
1852 else: 1957 else:
1853 return (basestate, self._tzinfo) 1958 return (basestate, self._tzinfo)
1854 1959
1855 def __setstate(self, string, tzinfo): 1960 def __setstate(self, string, tzinfo):
1856 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class): 1961 if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):
1857 raise TypeError("bad tzinfo state arg") 1962 raise TypeError("bad tzinfo state arg")
1858 (yhi, ylo, self._month, self._day, self._hour, 1963 (yhi, ylo, m, self._day, self._hour,
1859 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
1860 self._year = yhi * 256 + ylo 1971 self._year = yhi * 256 + ylo
1861 self._microsecond = (((us1 << 8) | us2) << 8) | us3 1972 self._microsecond = (((us1 << 8) | us2) << 8) | us3
1862 self._tzinfo = tzinfo 1973 self._tzinfo = tzinfo
1863 1974
1864 def __reduce__(self): 1975 def __reduce_ex__(self, protocol):
1865 return (self.__class__, self._getstate()) 1976 return (self.__class__, self._getstate(protocol))
1866 1977
1867 1978
1868 datetime.min = datetime(1, 1, 1) 1979 datetime.min = datetime(1, 1, 1)
1869 datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999) 1980 datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
1870 datetime.resolution = timedelta(microseconds=1) 1981 datetime.resolution = timedelta(microseconds=1)
1871 1982
1872 1983
1873 def _isoweek1monday(year): 1984 def _isoweek1monday(year):
1874 # 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
1875 # 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
2188 # 2299 #
2189 # 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
2190 # "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
2191 # 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
2192 # 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
2193 # 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
2194 # 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
2195 # 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.
2196 2307
2197 try: 2308 try:
2309 raise ImportError
2198 from _datetime import * 2310 from _datetime import *
2199 except ImportError: 2311 except ImportError:
2200 pass 2312 pass
2201 else: 2313 else:
2202 # Clean up unused names 2314 # Clean up unused names
2203 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y, 2315 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2204 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time, 2316 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2205 _check_date_fields, _check_int_field, _check_time_fields, 2317 _check_date_fields, _check_int_field, _check_time_fields,
2206 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror, 2318 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2207 _date_class, _days_before_month, _days_before_year, _days_in_month, 2319 _date_class, _days_before_month, _days_before_year, _days_in_month,
2208 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd, 2320 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2209 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord) 2321 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
2210 # XXX Since import * above excludes names that start with _, 2322 # XXX Since import * above excludes names that start with _,
2211 # docstring does not get overwritten. In the future, it may be 2323 # docstring does not get overwritten. In the future, it may be
2212 # appropriate to maintain a single module level docstring and 2324 # appropriate to maintain a single module level docstring and
2213 # remove the following line. 2325 # remove the following line.
2214 from _datetime import __doc__ 2326 from _datetime import __doc__
LEFTRIGHT

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