|
1 | 1 | # -*- coding: utf-8 -*-
|
2 | 2 | # cython: profile=False
|
3 | 3 | import collections
|
| 4 | +import re |
4 | 5 |
|
5 | 6 | import sys
|
6 | 7 | cdef bint PY3 = (sys.version_info[0] >= 3)
|
@@ -235,6 +236,25 @@ cpdef inline int64_t cast_from_unit(object ts, object unit) except? -1:
|
235 | 236 | return <int64_t> (base *m) + <int64_t> (frac *m)
|
236 | 237 |
|
237 | 238 |
|
| 239 | +cpdef match_iso_format(object ts): |
| 240 | + """ |
| 241 | + Match a provided string against an ISO 8601 pattern, providing a group for |
| 242 | + each ``Timedelta`` component. |
| 243 | + """ |
| 244 | + pater = re.compile(r"""P |
| 245 | + (?P<days>-?[0-9]*)DT |
| 246 | + (?P<hours>[0-9]{1,2})H |
| 247 | + (?P<minutes>[0-9]{1,2})M |
| 248 | + (?P<seconds>[0-9]{0,2}) |
| 249 | + (\. |
| 250 | + (?P<milliseconds>[0-9]{0,3}) |
| 251 | + (?P<microseconds>[0-9]{0,3}) |
| 252 | + (?P<nanoseconds>[0-9]{0,3}) |
| 253 | + )?S""", re.VERBOSE) |
| 254 | + |
| 255 | + return re.match(pater, ts) |
| 256 | + |
| 257 | + |
238 | 258 | cdef inline parse_timedelta_string(object ts):
|
239 | 259 | """
|
240 | 260 | Parse a regular format timedelta string. Return an int64_t (in ns)
|
@@ -506,6 +526,33 @@ def _binary_op_method_timedeltalike(op, name):
|
506 | 526 | # ----------------------------------------------------------------------
|
507 | 527 | # Timedelta Construction
|
508 | 528 |
|
| 529 | +def _value_from_iso_match(match): |
| 530 | + """ |
| 531 | + Extracts and cleanses the appropriate values from a match object with |
| 532 | + groups for each component of an ISO 8601 duration |
| 533 | +
|
| 534 | + Parameters |
| 535 | + ---------- |
| 536 | + match: |
| 537 | + Regular expression with groups for each component of an ISO 8601 |
| 538 | + duration |
| 539 | +
|
| 540 | + Returns |
| 541 | + ------- |
| 542 | + int |
| 543 | + Precision in nanoseconds of matched ISO 8601 duration |
| 544 | + """ |
| 545 | + match_dict = {k: v for k, v in match.groupdict().items() if v} |
| 546 | + for comp in ['milliseconds', 'microseconds', 'nanoseconds']: |
| 547 | + if comp in match_dict: |
| 548 | + match_dict[comp] ='{:0<3}'.format(match_dict[comp]) |
| 549 | + |
| 550 | + match_dict = {k: int(v) for k, v in match_dict.items()} |
| 551 | + nano = match_dict.pop('nanoseconds', 0) |
| 552 | + |
| 553 | + return nano + convert_to_timedelta64(timedelta(**match_dict), 'ns') |
| 554 | + |
| 555 | + |
509 | 556 | cdef _to_py_int_float(v):
|
510 | 557 | # Note: This used to be defined inside Timedelta.__new__
|
511 | 558 | # but cython will not allow `cdef` functions to be defined dynamically.
|
@@ -825,7 +872,11 @@ class Timedelta(_Timedelta):
|
825 | 872 | if isinstance(value, Timedelta):
|
826 | 873 | value = value.value
|
827 | 874 | elif is_string_object(value):
|
828 |
| - value = np.timedelta64(parse_timedelta_string(value)) |
| 875 | + if len(value) > 0 and value[0] == 'P': # hackish |
| 876 | + match = match_iso_format(value) |
| 877 | + value = _value_from_iso_match(match) |
| 878 | + else: |
| 879 | + value = np.timedelta64(parse_timedelta_string(value)) |
829 | 880 | elif PyDelta_Check(value):
|
830 | 881 | value = convert_to_timedelta64(value, 'ns')
|
831 | 882 | elif is_timedelta64_object(value):
|
|
0 commit comments