|
38 | 38 |
|
39 | 39 | _NOW = datetime.datetime.utcnow # To be replaced by tests.
|
40 | 40 | _RFC3339_MICROS = '%Y-%m-%dT%H:%M:%S.%fZ'
|
41 |
| -_RFC3339_NO_FRACTION_NO_ZULU = '%Y-%m-%dT%H:%M:%S' |
| 41 | +_RFC3339_NO_FRACTION = '%Y-%m-%dT%H:%M:%S' |
| 42 | +# datetime.strptime cannot handle nanosecond precision: parse w/ regex |
| 43 | +_RFC3339_NANOS = re.compile(r""" |
| 44 | + (?P<no_fraction> |
| 45 | + \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2} # YYYY-MM-DDTHH:MM:SS |
| 46 | + ) |
| 47 | + \. # decimal point |
| 48 | + (?P<nanos>\d{9}) # nanoseconds |
| 49 | + Z # Zulu |
| 50 | +""", re.VERBOSE) |
42 | 51 |
|
43 | 52 |
|
44 | 53 | class _LocalStack(Local):
|
@@ -319,15 +328,14 @@ def _rfc3339_to_datetime(dt_str):
|
319 | 328 | return datetime.datetime.strptime(
|
320 | 329 | dt_str, _RFC3339_MICROS).replace(tzinfo=UTC)
|
321 | 330 | except ValueError: # maybe nanosecond resoultion
|
322 |
| - prefix, suffix = dt_str.split('.') |
323 |
| - fraction, zulu = suffix[:-1], suffix[-1] |
324 |
| - if zulu == 'Z' and len(fraction) == 9: # nanoseconds |
325 |
| - nanos = int(fraction) |
326 |
| - micros = nanos // 1000 |
327 |
| - bare_seconds = datetime.datetime.strptime( |
328 |
| - prefix, _RFC3339_NO_FRACTION_NO_ZULU) |
329 |
| - return bare_seconds.replace(microsecond=micros, tzinfo=UTC) |
330 |
| - raise |
| 331 | + with_nanos = _RFC3339_NANOS.match(dt_str) |
| 332 | + if with_nanos is None: |
| 333 | + raise |
| 334 | + bare_seconds = datetime.datetime.strptime( |
| 335 | + with_nanos.group('no_fraction'), _RFC3339_NO_FRACTION) |
| 336 | + nanos = int(with_nanos.group('nanos')) |
| 337 | + micros = nanos // 1000 |
| 338 | + return bare_seconds.replace(microsecond=micros, tzinfo=UTC) |
331 | 339 |
|
332 | 340 |
|
333 | 341 | def _datetime_to_rfc3339(value):
|
|
0 commit comments