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

## Side by Side Diff: Lib/datetime.py

Issue 15873: "datetime" cannot parse ISO 8601 dates and times
Patch Set: Created 3 years, 11 months ago
 Left: Base Patch Set 1: None Patch Set 2: None Patch Set 3: None Patch Set 4: None Patch Set 5: None Patch Set 6: None Patch Set 7: None Patch Set 8: None Patch Set 9: None Patch Set 10: None Patch Set 11: None Patch Set 12: None Right: Patch Set 1: None Patch Set 2: None Patch Set 3: None Patch Set 4: None Patch Set 5: None Patch Set 6: None Patch Set 7: None Patch Set 8: None Patch Set 9: None Patch Set 10: None Patch Set 11: None Patch Set 12: None
« no previous file with comments | « no previous file | Lib/test/datetimetester.py » ('j') | no next file with comments »
OLDNEW
1 """Concrete date/time and related types. 1 """Concrete date/time and related types.
2 2
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 120 matching lines...)
139 140
140 # 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
141 # start of that month: we're done! 142 # start of that month: we're done!
142 return year, month, n+1 143 return year, month, n+1
143 144
144 # Month and day names. For localized versions, see the calendar module. 145 # Month and day names. For localized versions, see the calendar module.
145 _MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun", 146 _MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
146 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 147 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
147 _DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] 148 _DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
148 149
150 datetime_re = re.compile(
151 r'(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})'
152 r'[T ](?P<hour>\d{1,2}):(?P<minute>\d{1,2})'
153 r'(?::(?P<second>\d{1,2})(?:\.(?P<microsecond>\d{1,6})\d{0,6})?)?'
SilentGhost 2016/02/14 14:07:32 You're not testing the case with more than six dig
154 r'(?P<tzinfo>Z|[+-]\d{2}(?::?\d{2})?)?\$'
155 )
149 156
150 def _build_struct_time(y, m, d, hh, mm, ss, dstflag): 157 def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
151 wday = (_ymd2ord(y, m, d) + 6) % 7 158 wday = (_ymd2ord(y, m, d) + 6) % 7
152 dnum = _days_before_month(y, m) + d 159 dnum = _days_before_month(y, m) + d
153 return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag)) 160 return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
154 161
155 def _format_time(hh, mm, ss, us): 162 def _format_time(hh, mm, ss, us):
156 # Skip trailing microseconds when us==0. 163 # Skip trailing microseconds when us==0.
157 result = "%02d:%02d:%02d" % (hh, mm, ss) 164 result = "%02d:%02d:%02d" % (hh, mm, ss)
158 if us: 165 if us:
(...skipping 1233 matching lines...)
1392 """Construct a datetime from a POSIX timestamp (like time.time()). 1399 """Construct a datetime from a POSIX timestamp (like time.time()).
1393 1400
1394 A timezone info object may be passed in as well. 1401 A timezone info object may be passed in as well.
1395 """ 1402 """
1396 _check_tzinfo_arg(tz) 1403 _check_tzinfo_arg(tz)
1397 1404
1398 result = cls._fromtimestamp(t, tz is not None, tz) 1405 result = cls._fromtimestamp(t, tz is not None, tz)
1399 if tz is not None: 1406 if tz is not None:
1400 result = tz.fromutc(result) 1407 result = tz.fromutc(result)
1401 return 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
1417 Raises ValueError if the input is well formatted but not a valid datetim e.
1418 Returns None if the input isn't well formatted.
SilentGhost 2016/02/14 14:07:32 This doesn't strike me as a reasonable interface.
1419 """
1420 match = datetime_re.match(value)
1421 if match:
1422 kw = match.groupdict()
1423 if kw['microsecond']:
1424 kw['microsecond'] = kw['microsecond'].ljust(6, '0')
1425 tzinfo = kw.pop('tzinfo')
1426 if tzinfo == 'Z':
1427 tzinfo = timezone.utc
1428 elif tzinfo is not None:
1429 offset_mins = int(tzinfo[-2:]) if len(tzinfo) > 3 else 0
1430 offset_hours = int(tzinfo[1:3])
1431 offset = timedelta(hours=offset_hours, minutes=offset_mins)
1432 if tzinfo[0] == '-':
1433 offset = -offset
1434 tzinfo = timezone(offset)
1435 kw = {k: int(v) for k, v in kw.items() if v is not None}
1436 kw['tzinfo'] = tzinfo
1437 return cls(**kw)
1402 1438
1403 @classmethod 1439 @classmethod
1404 def utcfromtimestamp(cls, t): 1440 def utcfromtimestamp(cls, t):
1405 """Construct a naive UTC datetime from a POSIX timestamp.""" 1441 """Construct a naive UTC datetime from a POSIX timestamp."""
1406 return cls._fromtimestamp(t, True, None) 1442 return cls._fromtimestamp(t, True, None)
1407 1443
1408 @classmethod 1444 @classmethod
1409 def now(cls, tz=None): 1445 def now(cls, tz=None):
1410 "Construct a datetime from time.time() and optional time zone info." 1446 "Construct a datetime from time.time() and optional time zone info."
1411 t = _time.time() 1447 t = _time.time()
(...skipping 725 matching lines...)
2137 _check_date_fields, _check_int_field, _check_time_fields, 2173 _check_date_fields, _check_int_field, _check_time_fields,
2138 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror, 2174 _check_tzinfo_arg, _check_tzname, _check_utc_offset, _cmp, _cmperror,
2139 _date_class, _days_before_month, _days_before_year, _days_in_month, 2175 _date_class, _days_before_month, _days_before_year, _days_in_month,
2140 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd, 2176 _format_time, _is_leap, _isoweek1monday, _math, _ord2ymd,
2141 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord) 2177 _time, _time_class, _tzinfo_class, _wrap_strftime, _ymd2ord)
2142 # XXX Since import * above excludes names that start with _, 2178 # XXX Since import * above excludes names that start with _,
2143 # docstring does not get overwritten. In the future, it may be 2179 # docstring does not get overwritten. In the future, it may be
2144 # appropriate to maintain a single module level docstring and 2180 # appropriate to maintain a single module level docstring and
2145 # remove the following line. 2181 # remove the following line.
2146 from _datetime import __doc__ 2182 from _datetime import __doc__
OLDNEW
« no previous file with comments | « no previous file | Lib/test/datetimetester.py » ('j') | no next file with comments »

This is Rietveld 894c83f36cb7+