Skip to content

Commit

Permalink
ENH: Parse %z directive in format for to_datetime
Browse files Browse the repository at this point in the history
return timedeltas as list

return timedeltas in a numpy array

some flake fixes
  • Loading branch information
mroeschke committed Mar 3, 2018
1 parent 0bfb61b commit 9f273c4
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 4 deletions.
50 changes: 47 additions & 3 deletions pandas/_libs/tslibs/strptime.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ cimport cython
import numpy as np
from numpy cimport ndarray, int64_t

from datetime import date as datetime_date
from datetime import (date as datetime_date, timedelta as datetime_timedelta,
timezone as datetime_timezone)
from cpython.datetime cimport datetime

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

results_tz = np.empty(n, dtype='object')

dts.us = dts.ps = dts.as = 0

cdef dict _parse_code_table = {
Expand All @@ -130,7 +134,8 @@ def array_strptime(ndarray[object] values, object fmt,
'U': 15,
'W': 16,
'Z': 17,
'p': 18 # just an additional key, works only with I
'p': 18, # just an additional key, works only with I
'z': 19,
}
cdef int parse_code

Expand Down Expand Up @@ -177,6 +182,8 @@ def array_strptime(ndarray[object] values, object fmt,
month = day = 1
hour = minute = second = ns = us = 0
tz = -1
gmtoff = None
gmtoff_fraction = 0
# Default to -1 to signify that values not known; not critical to have,
# though
week_of_year = -1
Expand Down Expand Up @@ -281,6 +288,32 @@ def array_strptime(ndarray[object] values, object fmt,
else:
tz = value
break
elif parse_code == 19:
z = found_dict['z']
if z == 'Z':
gmtoff = 0
else:
if z[3] == ':':
z = z[:3] + z[4:]
if len(z) > 5:
if z[5] != ':':
msg = "Unconsistent use of : in {0}"
raise ValueError(msg.format(found_dict['z']))
z = z[:5] + z[6:]
hours = int(z[1:3])
minutes = int(z[3:5])
seconds = int(z[5:7] or 0)
gmtoff = (hours * 60 * 60) + (minutes * 60) + seconds
gmtoff_remainder = z[8:]
# Pad to always return microseconds.
pad_number = 6 - len(gmtoff_remainder)
gmtoff_remainder_padding = "0" * pad_number
gmtoff_fraction = int(gmtoff_remainder +
gmtoff_remainder_padding)
if z.startswith("-"):
gmtoff = -gmtoff
gmtoff_fraction = -gmtoff_fraction

# If we know the wk of the year and what day of that wk, we can figure
# out the Julian day of the year.
if julian == -1 and week_of_year != -1 and weekday != -1:
Expand Down Expand Up @@ -330,7 +363,17 @@ def array_strptime(ndarray[object] values, object fmt,
continue
raise

return result
if gmtoff is not None:
tzdelta = datetime_timedelta(seconds=gmtoff,
microseconds=gmtoff_fraction)
tzname = found_dict.get('Z')
if tzname:
tzinfo = datetime_timezone(tzdelta, tzname)
else:
tzinfo = datetime_timezone(tzdelta, tzname)
results_tz[i] = tzinfo

return result, results_tz


"""_getlang, LocaleTime, TimeRE, _calc_julian_from_U_or_W are vendored
Expand Down Expand Up @@ -538,6 +581,7 @@ class TimeRE(dict):
# XXX: Does 'Y' need to worry about having less or more than
# 4 digits?
'Y': r"(?P<Y>\d\d\d\d)",
'z': r"(?P<z>[+-]\d\d:?[0-5]\d(:?[0-5]\d(\.\d{1,6})?)?|Z)",
'A': self.__seqToRE(self.locale_time.f_weekday, 'A'),
'a': self.__seqToRE(self.locale_time.a_weekday, 'a'),
'B': self.__seqToRE(self.locale_time.f_month[1:], 'B'),
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/tools/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ def _convert_listlike(arg, box, format, name=None, tz=tz):
if result is None:
try:
result = array_strptime(arg, format, exact=exact,
errors=errors)
errors=errors)[0]
except tslib.OutOfBoundsDatetime:
if errors == 'raise':
raise
Expand Down

0 comments on commit 9f273c4

Please sign in to comment.