@@ -29,7 +29,8 @@ cimport cython
2929import numpy as np
3030from 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)
3334from cpython.datetime cimport datetime
3435
3536from 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' ),
0 commit comments