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

Side by Side Diff: Lib/datetime.py

Issue 15873: "datetime" cannot parse ISO 8601 dates and times
Patch Set: Created 4 years 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:
View unified diff | Download patch
« no previous file with comments | « no previous file | Lib/test/datetimetester.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
10
9 11
10 def _cmp(x, y): 12 def _cmp(x, y):
11 return 0 if x == y else 1 if x > y else -1 13 return 0 if x == y else 1 if x > y else -1
12 14
13 MINYEAR = 1 15 MINYEAR = 1
14 MAXYEAR = 9999 16 MAXYEAR = 9999
15 _MAXORDINAL = 3652059 # date.max.toordinal() 17 _MAXORDINAL = 3652059 # date.max.toordinal()
16 18
17 # Utility functions, adapted from Python's Demo/classes/Dates.py, which 19 # Utility functions, adapted from Python's Demo/classes/Dates.py, which
18 # also assumes the current Gregorian calendar indefinitely extended in 20 # also assumes the current Gregorian calendar indefinitely extended in
(...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 def _getstate(self): 633 def _getstate(self):
632 return (self._days, self._seconds, self._microseconds) 634 return (self._days, self._seconds, self._microseconds)
633 635
634 def __reduce__(self): 636 def __reduce__(self):
635 return (self.__class__, self._getstate()) 637 return (self.__class__, self._getstate())
636 638
637 timedelta.min = timedelta(-999999999) 639 timedelta.min = timedelta(-999999999)
638 timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59, 640 timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
639 microseconds=999999) 641 microseconds=999999)
640 timedelta.resolution = timedelta(microseconds=1) 642 timedelta.resolution = timedelta(microseconds=1)
643
644 _DATE_RE = re.compile(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})$', re.AS CII)
641 645
642 class date: 646 class date:
643 """Concrete date type. 647 """Concrete date type.
644 648
645 Constructors: 649 Constructors:
646 650
647 __new__() 651 __new__()
648 fromtimestamp() 652 fromtimestamp()
649 today() 653 today()
650 fromordinal() 654 fromordinal()
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
707 711
708 @classmethod 712 @classmethod
709 def fromordinal(cls, n): 713 def fromordinal(cls, n):
710 """Contruct a date from a proleptic Gregorian ordinal. 714 """Contruct a date from a proleptic Gregorian ordinal.
711 715
712 January 1 of year 1 is day 1. Only the year, month and day are 716 January 1 of year 1 is day 1. Only the year, month and day are
713 non-zero in the result. 717 non-zero in the result.
714 """ 718 """
715 y, m, d = _ord2ymd(n) 719 y, m, d = _ord2ymd(n)
716 return cls(y, m, d) 720 return cls(y, m, d)
721
722 @classmethod
723 def fromisoformat(cls, date_string):
724 """Constructs a date from a RFC 3339 string, a strict subset of ISO 8601
Martin Panter 2016/02/18 02:45:42 an RFC 3339 string
deronnax 2016/08/05 14:09:51 Done.
725
726 raise ValueError in case of ill formatted or invalid string.
Martin Panter 2016/02/18 02:45:42 Capital R for Raise Hyphen for ill-formatted
deronnax 2016/08/05 14:09:51 Done.
727 """
728 m = _DATE_RE.match(date_string)
729 if not m:
730 raise ValueError('invalid RFC 3339 date string: "%s"' % date_string)
SilentGhost 2016/02/18 04:13:13 That would be better as %r (and without double-quo
deronnax 2016/08/05 14:09:51 Done.
731 kw = m.groupdict()
732 kw = {k: int(v) for k, v in kw.items()}
733 return cls(**kw)
717 734
718 # Conversions to string 735 # Conversions to string
719 736
720 def __repr__(self): 737 def __repr__(self):
721 """Convert to formal string, for repr(). 738 """Convert to formal string, for repr().
722 739
723 >>> dt = datetime(2010, 1, 1) 740 >>> dt = datetime(2010, 1, 1)
724 >>> repr(dt) 741 >>> repr(dt)
725 'datetime.datetime(2010, 1, 1, 0, 0)' 742 'datetime.datetime(2010, 1, 1, 0, 0)'
726 743
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after
995 if getstate: 1012 if getstate:
996 state = getstate() 1013 state = getstate()
997 else: 1014 else:
998 state = getattr(self, "__dict__", None) or None 1015 state = getattr(self, "__dict__", None) or None
999 if state is None: 1016 if state is None:
1000 return (self.__class__, args) 1017 return (self.__class__, args)
1001 else: 1018 else:
1002 return (self.__class__, args, state) 1019 return (self.__class__, args, state)
1003 1020
1004 _tzinfo_class = tzinfo 1021 _tzinfo_class = tzinfo
1022
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)
1005 1026
1006 class time: 1027 class time:
1007 """Time with time zone. 1028 """Time with time zone.
1008 1029
1009 Constructors: 1030 Constructors:
1010 1031
1011 __new__() 1032 __new__()
1012 1033
1013 Operators: 1034 Operators:
1014 1035
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1047 hour, minute, second, microsecond) 1068 hour, minute, second, microsecond)
1048 _check_tzinfo_arg(tzinfo) 1069 _check_tzinfo_arg(tzinfo)
1049 self = object.__new__(cls) 1070 self = object.__new__(cls)
1050 self._hour = hour 1071 self._hour = hour
1051 self._minute = minute 1072 self._minute = minute
1052 self._second = second 1073 self._second = second
1053 self._microsecond = microsecond 1074 self._microsecond = microsecond
1054 self._tzinfo = tzinfo 1075 self._tzinfo = tzinfo
1055 self._hashcode = -1 1076 self._hashcode = -1
1056 return self 1077 return self
1078
1079 @staticmethod
1080 def _parse_isotime(reg, isostring, objekt):
Martin Panter 2016/02/18 02:45:42 Spelling: object (or maybe class_name if you don’t
deronnax 2016/08/05 14:09:51 Done.
1081 match = reg.match(isostring)
1082 if not match:
1083 raise ValueError('invalid RFC 3339 %s string: "%s"' % (objekt, isost ring))
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:].split(':')
SilentGhost 2016/02/18 04:13:13 .partition would be more appropriate here.
deronnax 2016/08/05 14:09:51 Done.
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
SilentGhost 2016/02/18 04:13:13 If you're to make this assignment conditional on t
deronnax 2016/08/05 14:09:51 But the "if tzinfo" and if kw.pop('microsecond') w
1100 return kw
1101
1102 @classmethod
1103 def fromisoformat(cls, time_string):
1104 """Constructs a time from a RFC 3339 string, a strict subset of ISO 8601
1105
1106 Microseconds are rounded to 6 digits.
1107 raise ValueError in case of ill formatted or invalid string
Martin Panter 2016/02/18 02:45:42 Missing full stop (.) at the end.
deronnax 2016/08/05 14:09:51 Done.
1108 """
1109 kw = cls._parse_isotime(_TIME_RE, time_string, cls.__name__)
1110 return cls(**kw)
1111
1057 1112
1058 # Read-only field accessors 1113 # Read-only field accessors
1059 @property 1114 @property
1060 def hour(self): 1115 def hour(self):
1061 """hour (0-23)""" 1116 """hour (0-23)"""
1062 return self._hour 1117 return self._hour
1063 1118
1064 @property 1119 @property
1065 def minute(self): 1120 def minute(self):
1066 """minute (0-59)""" 1121 """minute (0-59)"""
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
1301 self._tzinfo = tzinfo 1356 self._tzinfo = tzinfo
1302 1357
1303 def __reduce__(self): 1358 def __reduce__(self):
1304 return (time, self._getstate()) 1359 return (time, self._getstate())
1305 1360
1306 _time_class = time # so functions w/ args named "time" can get at the class 1361 _time_class = time # so functions w/ args named "time" can get at the class
1307 1362
1308 time.min = time(0, 0, 0) 1363 time.min = time(0, 0, 0)
1309 time.max = time(23, 59, 59, 999999) 1364 time.max = time(23, 59, 59, 999999)
1310 time.resolution = timedelta(microseconds=1) 1365 time.resolution = timedelta(microseconds=1)
1366
1367 _DATETIME_RE = re.compile(_DATE_RE.pattern[:-1] + r'[T ]' + _TIME_RE.pattern,
SilentGhost 2016/02/18 04:13:13 raw string literal is not needed here
deronnax 2016/08/05 14:09:51 It was for consistency with the other regex, when
1368 re.ASCII|re.IGNORECASE)
1311 1369
1312 class datetime(date): 1370 class datetime(date):
1313 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo] ]]]]) 1371 """datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo] ]]]])
1314 1372
1315 The year, month and day arguments are required. tzinfo may be None, or an 1373 The year, month and day arguments are required. tzinfo may be None, or an
1316 instance of a tzinfo subclass. The remaining arguments may be ints. 1374 instance of a tzinfo subclass. The remaining arguments may be ints.
1317 """ 1375 """
1318 __slots__ = date.__slots__ + time.__slots__ 1376 __slots__ = date.__slots__ + time.__slots__
1319 1377
1320 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0, 1378 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
1420 @classmethod 1478 @classmethod
1421 def combine(cls, date, time): 1479 def combine(cls, date, time):
1422 "Construct a datetime from a given date and a given time." 1480 "Construct a datetime from a given date and a given time."
1423 if not isinstance(date, _date_class): 1481 if not isinstance(date, _date_class):
1424 raise TypeError("date argument must be a date instance") 1482 raise TypeError("date argument must be a date instance")
1425 if not isinstance(time, _time_class): 1483 if not isinstance(time, _time_class):
1426 raise TypeError("time argument must be a time instance") 1484 raise TypeError("time argument must be a time instance")
1427 return cls(date.year, date.month, date.day, 1485 return cls(date.year, date.month, date.day,
1428 time.hour, time.minute, time.second, time.microsecond, 1486 time.hour, time.minute, time.second, time.microsecond,
1429 time.tzinfo) 1487 time.tzinfo)
1488
1489 @classmethod
1490 def fromisoformat(cls, datetime_string):
1491 """Constructs a datetime from a 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)
1430 1498
1431 def timetuple(self): 1499 def timetuple(self):
1432 "Return local time tuple compatible with time.localtime()." 1500 "Return local time tuple compatible with time.localtime()."
1433 dst = self.dst() 1501 dst = self.dst()
1434 if dst is None: 1502 if dst is None:
1435 dst = -1 1503 dst = -1
1436 elif dst: 1504 elif dst:
1437 dst = 1 1505 dst = 1
1438 else: 1506 else:
1439 dst = 0 1507 dst = 0
(...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after
2120 # 2188 #
2121 # In any case, it's clear that the default fromutc() is strong enough to handle 2189 # In any case, it's clear that the default fromutc() is strong enough to handle
2122 # "almost all" time zones: so long as the standard offset is invariant, it 2190 # "almost all" time zones: so long as the standard offset is invariant, it
2123 # doesn't matter if daylight time transition points change from year to year, or 2191 # doesn't matter if daylight time transition points change from year to year, or
2124 # if daylight time is skipped in some years; it doesn't matter how large or 2192 # if daylight time is skipped in some years; it doesn't matter how large or
2125 # small dst() may get within its bounds; and it doesn't even matter if some 2193 # small dst() may get within its bounds; and it doesn't even matter if some
2126 # perverse time zone returns a negative dst()). So a breaking case must be 2194 # perverse time zone returns a negative dst()). So a breaking case must be
2127 # pretty bizarre, and a tzinfo subclass can override fromutc() if it is. 2195 # pretty bizarre, and a tzinfo subclass can override fromutc() if it is.
2128 2196
2129 try: 2197 try:
2198 raise ImportError
SilentGhost 2016/02/18 04:13:13 This line is from your local setup, I believe.
deronnax 2016/08/05 14:09:51 Yes. I usually remove it before patch generation,
2130 from _datetime import * 2199 from _datetime import *
2131 except ImportError: 2200 except ImportError:
2132 pass 2201 pass
2133 else: 2202 else:
2134 # Clean up unused names 2203 # Clean up unused names
2135 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y, 2204 del (_DAYNAMES, _DAYS_BEFORE_MONTH, _DAYS_IN_MONTH, _DI100Y, _DI400Y,
2136 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time, 2205 _DI4Y, _EPOCH, _MAXORDINAL, _MONTHNAMES, _build_struct_time,
2137 _check_date_fields, _check_int_field, _check_time_fields, 2206 _check_date_fields, _check_int_field, _check_time_fields,
2138 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror, 2207 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2139 _date_class, _days_before_month, _days_before_year, _days_in_month, 2208 _date_class, _days_before_month, _days_before_year, _days_in_month,
2140 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd, 2209 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2141 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord) 2210 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
2142 # XXX Since import * above excludes names that start with _, 2211 # XXX Since import * above excludes names that start with _,
2143 # docstring does not get overwritten. In the future, it may be 2212 # docstring does not get overwritten. In the future, it may be
2144 # appropriate to maintain a single module level docstring and 2213 # appropriate to maintain a single module level docstring and
2145 # remove the following line. 2214 # remove the following line.
2146 from _datetime import __doc__ 2215 from _datetime import __doc__
OLDNEW
« no previous file with comments | « no previous file | Lib/test/datetimetester.py » ('j') | no next file with comments »

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