Skip to content

Commit 7592ed8

Browse files
committed
ENH: Parse %z directive in format for to_datetime
return timedeltas as list return timedeltas in a numpy array some flake fixes
1 parent 1d73cf3 commit 7592ed8

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

pandas/_libs/tslibs/strptime.pyx

+47-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ cimport cython
2929
import numpy as np
3030
from numpy cimport ndarray, int64_t
3131

32-
from datetime import date as datetime_date
32+
from datetime import (date as datetime_date, timedelta as datetime_timedelta,
33+
timezone as datetime_timezone)
3334
from cpython.datetime cimport datetime
3435

3536
from np_datetime cimport (check_dts_bounds,
@@ -58,6 +59,7 @@ def array_strptime(ndarray[object] values, object fmt,
5859
Py_ssize_t i, n = len(values)
5960
pandas_datetimestruct dts
6061
ndarray[int64_t] iresult
62+
ndarray[object] results_tz
6163
int year, month, day, minute, hour, second, weekday, julian, tz
6264
int week_of_year, week_of_year_start
6365
int64_t us, ns
@@ -109,6 +111,8 @@ def array_strptime(ndarray[object] values, object fmt,
109111
result = np.empty(n, dtype='M8[ns]')
110112
iresult = result.view('i8')
111113

114+
results_tz = np.empty(n, dtype='object')
115+
112116
dts.us = dts.ps = dts.as = 0
113117

114118
cdef dict _parse_code_table = {
@@ -130,7 +134,8 @@ def array_strptime(ndarray[object] values, object fmt,
130134
'U': 15,
131135
'W': 16,
132136
'Z': 17,
133-
'p': 18 # just an additional key, works only with I
137+
'p': 18, # just an additional key, works only with I
138+
'z': 19,
134139
}
135140
cdef int parse_code
136141

@@ -177,6 +182,8 @@ def array_strptime(ndarray[object] values, object fmt,
177182
month = day = 1
178183
hour = minute = second = ns = us = 0
179184
tz = -1
185+
gmtoff = None
186+
gmtoff_fraction = 0
180187
# Default to -1 to signify that values not known; not critical to have,
181188
# though
182189
week_of_year = -1
@@ -281,6 +288,32 @@ def array_strptime(ndarray[object] values, object fmt,
281288
else:
282289
tz = value
283290
break
291+
elif parse_code == 19:
292+
z = found_dict['z']
293+
if z == 'Z':
294+
gmtoff = 0
295+
else:
296+
if z[3] == ':':
297+
z = z[:3] + z[4:]
298+
if len(z) > 5:
299+
if z[5] != ':':
300+
msg = "Unconsistent use of : in {0}"
301+
raise ValueError(msg.format(found_dict['z']))
302+
z = z[:5] + z[6:]
303+
hours = int(z[1:3])
304+
minutes = int(z[3:5])
305+
seconds = int(z[5:7] or 0)
306+
gmtoff = (hours * 60 * 60) + (minutes * 60) + seconds
307+
gmtoff_remainder = z[8:]
308+
# Pad to always return microseconds.
309+
pad_number = 6 - len(gmtoff_remainder)
310+
gmtoff_remainder_padding = "0" * pad_number
311+
gmtoff_fraction = int(gmtoff_remainder +
312+
gmtoff_remainder_padding)
313+
if z.startswith("-"):
314+
gmtoff = -gmtoff
315+
gmtoff_fraction = -gmtoff_fraction
316+
284317
# If we know the wk of the year and what day of that wk, we can figure
285318
# out the Julian day of the year.
286319
if julian == -1 and week_of_year != -1 and weekday != -1:
@@ -330,7 +363,17 @@ def array_strptime(ndarray[object] values, object fmt,
330363
continue
331364
raise
332365

333-
return result
366+
if gmtoff is not None:
367+
tzdelta = datetime_timedelta(seconds=gmtoff,
368+
microseconds=gmtoff_fraction)
369+
tzname = found_dict.get('Z')
370+
if tzname:
371+
tzinfo = datetime_timezone(tzdelta, tzname)
372+
else:
373+
tzinfo = datetime_timezone(tzdelta, tzname)
374+
results_tz[i] = tzinfo
375+
376+
return result, results_tz
334377

335378

336379
"""_getlang, LocaleTime, TimeRE, _calc_julian_from_U_or_W are vendored
@@ -538,6 +581,7 @@ class TimeRE(dict):
538581
# XXX: Does 'Y' need to worry about having less or more than
539582
# 4 digits?
540583
'Y': r"(?P<Y>\d\d\d\d)",
584+
'z': r"(?P<z>[+-]\d\d:?[0-5]\d(:?[0-5]\d(\.\d{1,6})?)?|Z)",
541585
'A': self.__seqToRE(self.locale_time.f_weekday, 'A'),
542586
'a': self.__seqToRE(self.locale_time.a_weekday, 'a'),
543587
'B': self.__seqToRE(self.locale_time.f_month[1:], 'B'),

pandas/core/tools/datetimes.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ def _convert_listlike(arg, box, format, name=None, tz=tz):
344344
if result is None:
345345
try:
346346
result = array_strptime(arg, format, exact=exact,
347-
errors=errors)
347+
errors=errors)[0]
348348
except tslib.OutOfBoundsDatetime:
349349
if errors == 'raise':
350350
raise

0 commit comments

Comments
 (0)