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

Delta Between Two Patch Sets: Lib/datetime.py

Issue 15873: "datetime" cannot parse ISO 8601 dates and times
Left Patch Set: Created 3 years, 6 months 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 10
10 def _cmp(x, y): 11 def _cmp(x, y):
11 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
12 13
13 MINYEAR = 1 14 MINYEAR = 1
14 MAXYEAR = 9999 15 MAXYEAR = 9999
15 _MAXORDINAL = 3652059 # date.max.toordinal() 16 _MAXORDINAL = 3652059 # date.max.toordinal()
16 17
17 # Utility functions, adapted from Python's Demo/classes/Dates.py, which 18 # Utility functions, adapted from Python's Demo/classes/Dates.py, which
18 # also assumes the current Gregorian calendar indefinitely extended in 19 # also assumes the current Gregorian calendar indefinitely extended in
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 # 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
325 # positive, 2 * r < b if b negative. 326 # positive, 2 * r < b if b negative.
326 r *= 2 327 r *= 2
327 greater_than_half = r > b if b > 0 else r < b 328 greater_than_half = r > b if b > 0 else r < b
328 if greater_than_half or r == b and q % 2 == 1: 329 if greater_than_half or r == b and q % 2 == 1:
329 q += 1 330 q += 1
330 331
331 return q 332 return q
332 333
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)
358
359
334 class timedelta: 360 class timedelta:
335 """Represent the difference between two datetime objects. 361 """Represent the difference between two datetime objects.
336 362
337 Supported operators: 363 Supported operators:
338 364
339 - add, subtract timedelta 365 - add, subtract timedelta
340 - unary plus, minus, abs 366 - unary plus, minus, abs
341 - compare to timedelta 367 - compare to timedelta
342 - multiply, divide by int 368 - multiply, divide by int
343 369
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after
675 toordinal() 701 toordinal()
676 weekday() 702 weekday()
677 isoweekday(), isocalendar(), isoformat() 703 isoweekday(), isocalendar(), isoformat()
678 ctime() 704 ctime()
679 strftime() 705 strftime()
680 706
681 Properties (readonly): 707 Properties (readonly):
682 year, month, day 708 year, month, day
683 """ 709 """
684 __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)
685 713
686 def __new__(cls, year, month=None, day=None): 714 def __new__(cls, year, month=None, day=None):
687 """Constructor. 715 """Constructor.
688 716
689 Arguments: 717 Arguments:
690 718
691 year, month, day (required, base 1) 719 year, month, day (required, base 1)
692 """ 720 """
693 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 \
694 1 <= year[2] <= 12: 722 1 <= year[2] <= 12:
(...skipping 28 matching lines...) Expand all
723 def fromordinal(cls, n): 751 def fromordinal(cls, n):
724 """Construct a date from a proleptic Gregorian ordinal. 752 """Construct a date from a proleptic Gregorian ordinal.
725 753
726 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
727 non-zero in the result. 755 non-zero in the result.
728 """ 756 """
729 y, m, d = _ord2ymd(n) 757 y, m, d = _ord2ymd(n)
730 return cls(y, m, d) 758 return cls(y, m, d)
731 759
732 @classmethod 760 @classmethod
733 def fromisoformat(cls, string): 761 def fromisoformat(cls, date_string):
734 """Construct a date from an RFC 3339 string, a strict subset of ISO 8601 762 """Constructs a date from an RFC 3339 string, a strict subset of ISO 860 1
735 763
736 Raises ValueError in case of ill-formatted or invalid string. 764 Raises ValueError in case of ill-formatted or invalid string.
737 """ 765 """
738 import _strptime 766 return _parse_isotime(cls, date_string)
739 return _strptime._parse_isodatetime(cls, string)
740 767
741 # Conversions to string 768 # Conversions to string
742 769
743 def __repr__(self): 770 def __repr__(self):
744 """Convert to formal string, for repr(). 771 """Convert to formal string, for repr().
745 772
746 >>> dt = datetime(2010, 1, 1) 773 >>> dt = datetime(2010, 1, 1)
747 >>> repr(dt) 774 >>> repr(dt)
748 'datetime.datetime(2010, 1, 1, 0, 0)' 775 'datetime.datetime(2010, 1, 1, 0, 0)'
749 776
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after
1020 state = getstate() 1047 state = getstate()
1021 else: 1048 else:
1022 state = getattr(self, "__dict__", None) or None 1049 state = getattr(self, "__dict__", None) or None
1023 if state is None: 1050 if state is None:
1024 return (self.__class__, args) 1051 return (self.__class__, args)
1025 else: 1052 else:
1026 return (self.__class__, args, state) 1053 return (self.__class__, args, state)
1027 1054
1028 _tzinfo_class = tzinfo 1055 _tzinfo_class = tzinfo
1029 1056
1057
1030 class time: 1058 class time:
1031 """Time with time zone. 1059 """Time with time zone.
1032 1060
1033 Constructors: 1061 Constructors:
1034 1062
1035 __new__() 1063 __new__()
1036 1064
1037 Operators: 1065 Operators:
1038 1066
1039 __repr__, __str__ 1067 __repr__, __str__
1040 __eq__, __le__, __lt__, __ge__, __gt__, __hash__ 1068 __eq__, __le__, __lt__, __ge__, __gt__, __hash__
1041 1069
1042 Methods: 1070 Methods:
1043 1071
1044 strftime() 1072 strftime()
1045 isoformat() 1073 isoformat()
1046 utcoffset() 1074 utcoffset()
1047 tzname() 1075 tzname()
1048 dst() 1076 dst()
1049 1077
1050 Properties (readonly): 1078 Properties (readonly):
1051 hour, minute, second, microsecond, tzinfo, fold 1079 hour, minute, second, microsecond, tzinfo, fold
1052 """ 1080 """
1053 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hash code', '_fold' 1081 __slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hash code', '_fold'
1082
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
1054 1087
1055 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0): 1088 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
1056 """Constructor. 1089 """Constructor.
1057 1090
1058 Arguments: 1091 Arguments:
1059 1092
1060 hour, minute (required) 1093 hour, minute (required)
1061 second, microsecond (default to zero) 1094 second, microsecond (default to zero)
1062 tzinfo (default to None) 1095 tzinfo (default to None)
1063 fold (keyword only, default to True) 1096 fold (keyword only, default to True)
(...skipping 11 matching lines...) Expand all
1075 self._hour = hour 1108 self._hour = hour
1076 self._minute = minute 1109 self._minute = minute
1077 self._second = second 1110 self._second = second
1078 self._microsecond = microsecond 1111 self._microsecond = microsecond
1079 self._tzinfo = tzinfo 1112 self._tzinfo = tzinfo
1080 self._hashcode = -1 1113 self._hashcode = -1
1081 self._fold = fold 1114 self._fold = fold
1082 return self 1115 return self
1083 1116
1084 @classmethod 1117 @classmethod
1085 def fromisoformat(cls, string): 1118 def fromisoformat(cls, time_string):
1086 """Construct a time from an RFC 3339 string, a strict subset of ISO 8601 1119 """Constructs a time from an RFC 3339 string, a strict subset of ISO 860 1
1087 1120
1088 Microseconds are rounded to 6 digits. 1121 Microseconds are rounded to 6 digits.
1089 Raises ValueError in case of ill-formatted or invalid string. 1122 Raises ValueError in case of ill-formatted or invalid string.
1090 """ 1123 """
1091 import _strptime 1124 return _parse_isotime(cls, time_string)
1092 return _strptime._parse_isodatetime(cls, string)
1093 1125
1094 # Read-only field accessors 1126 # Read-only field accessors
1095 @property 1127 @property
1096 def hour(self): 1128 def hour(self):
1097 """hour (0-23)""" 1129 """hour (0-23)"""
1098 return self._hour 1130 return self._hour
1099 1131
1100 @property 1132 @property
1101 def minute(self): 1133 def minute(self):
1102 """minute (0-59)""" 1134 """minute (0-59)"""
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after
1371 time.max = time(23, 59, 59, 999999) 1403 time.max = time(23, 59, 59, 999999)
1372 time.resolution = timedelta(microseconds=1) 1404 time.resolution = timedelta(microseconds=1)
1373 1405
1374 class datetime(date): 1406 class datetime(date):
1375 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo] ]]]]) 1407 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo] ]]]])
1376 1408
1377 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
1378 instance of a tzinfo subclass. The remaining arguments may be ints. 1410 instance of a tzinfo subclass. The remaining arguments may be ints.
1379 """ 1411 """
1380 __slots__ = date.__slots__ + time.__slots__ 1412 __slots__ = date.__slots__ + time.__slots__
1413
1414 _isore = re.compile(date._isore.pattern[:-1] + r'[T ]' +
1415 time._isore.pattern, re.ASCII|re.IGNORECASE)
1381 1416
1382 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,
1383 microsecond=0, tzinfo=None, *, fold=0): 1418 microsecond=0, tzinfo=None, *, fold=0):
1384 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12: 1419 if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12:
1385 # Pickle support 1420 # Pickle support
1386 self = object.__new__(cls) 1421 self = object.__new__(cls)
1387 self.__setstate(year, month) 1422 self.__setstate(year, month)
1388 self._hashcode = -1 1423 self._hashcode = -1
1389 return self 1424 return self
1390 year, month, day = _check_date_fields(year, month, day) 1425 year, month, day = _check_date_fields(year, month, day)
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
1474 def fromtimestamp(cls, t, tz=None): 1509 def fromtimestamp(cls, t, tz=None):
1475 """Construct a datetime from a POSIX timestamp (like time.time()). 1510 """Construct a datetime from a POSIX timestamp (like time.time()).
1476 1511
1477 A timezone info object may be passed in as well. 1512 A timezone info object may be passed in as well.
1478 """ 1513 """
1479 _check_tzinfo_arg(tz) 1514 _check_tzinfo_arg(tz)
1480 1515
1481 return cls._fromtimestamp(t, tz is not None, tz) 1516 return cls._fromtimestamp(t, tz is not None, tz)
1482 1517
1483 @classmethod 1518 @classmethod
1484 def fromisoformat(cls, string):
1485 """Construct a datetime from an RFC 3339 string, a strict subset of ISO 8601
1486 microseconds are rounded to 6 digits.
1487
1488 Raises ValueError in case of ill-formatted or invalid string.
1489 """
1490 import _strptime
1491 return _strptime._parse_isodatetime(cls, string)
1492
1493 @classmethod
1494 def utcfromtimestamp(cls, t): 1519 def utcfromtimestamp(cls, t):
1495 """Construct a naive UTC datetime from a POSIX timestamp.""" 1520 """Construct a naive UTC datetime from a POSIX timestamp."""
1496 return cls._fromtimestamp(t, True, None) 1521 return cls._fromtimestamp(t, True, None)
1497 1522
1498 @classmethod 1523 @classmethod
1499 def now(cls, tz=None): 1524 def now(cls, tz=None):
1500 "Construct a datetime from time.time() and optional time zone info." 1525 "Construct a datetime from time.time() and optional time zone info."
1501 t = _time.time() 1526 t = _time.time()
1502 return cls.fromtimestamp(t, tz) 1527 return cls.fromtimestamp(t, tz)
1503 1528
(...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after
2274 # 2299 #
2275 # 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
2276 # "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
2277 # 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
2278 # 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
2279 # 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
2280 # 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
2281 # 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.
2282 2307
2283 try: 2308 try:
2309 raise ImportError
2284 from _datetime import * 2310 from _datetime import *
2285 except ImportError: 2311 except ImportError:
2286 pass 2312 pass
2287 else: 2313 else:
2288 # Clean up unused names 2314 # Clean up unused names
2289 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y, 2315 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2290 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time, 2316 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2291 _check_date_fields, _check_int_field, _check_time_fields, 2317 _check_date_fields, _check_int_field, _check_time_fields,
2292 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror, 2318 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2293 _date_class, _days_before_month, _days_before_year, _days_in_month, 2319 _date_class, _days_before_month, _days_before_year, _days_in_month,
2294 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd, 2320 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2295 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord) 2321 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
2296 # XXX Since import * above excludes names that start with _, 2322 # XXX Since import * above excludes names that start with _,
2297 # docstring does not get overwritten. In the future, it may be 2323 # docstring does not get overwritten. In the future, it may be
2298 # appropriate to maintain a single module level docstring and 2324 # appropriate to maintain a single module level docstring and
2299 # remove the following line. 2325 # remove the following line.
2300 from _datetime import __doc__ 2326 from _datetime import __doc__
LEFTRIGHT

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