@@ -24,6 +24,7 @@ from cpython.datetime cimport (
24
24
timedelta,
25
25
tzinfo,
26
26
)
27
+
27
28
from _strptime import (
28
29
TimeRE as _TimeRE,
29
30
_getlang,
@@ -46,8 +47,8 @@ from numpy cimport (
46
47
47
48
from pandas._libs.missing cimport checknull_with_nat_and_na
48
49
from pandas._libs.tslibs.conversion cimport (
49
- convert_timezone,
50
50
get_datetime64_nanos,
51
+ parse_pydatetime,
51
52
)
52
53
from pandas._libs.tslibs.nattype cimport (
53
54
NPY_NAT,
@@ -61,14 +62,13 @@ from pandas._libs.tslibs.np_datetime cimport (
61
62
npy_datetimestruct,
62
63
npy_datetimestruct_to_datetime,
63
64
pydate_to_dt64,
64
- pydatetime_to_dt64,
65
65
string_to_dts,
66
66
)
67
67
68
68
import_pandas_datetime()
69
69
70
70
from pandas._libs.tslibs.np_datetime import OutOfBoundsDatetime
71
- from pandas._libs.tslibs.timestamps cimport _Timestamp
71
+
72
72
from pandas._libs.util cimport (
73
73
is_datetime64_object,
74
74
is_float_object,
@@ -175,7 +175,7 @@ def array_strptime(
175
175
Py_ssize_t i, n = len (values)
176
176
npy_datetimestruct dts
177
177
int64_t[::1 ] iresult
178
- object [:: 1 ] result_timezone
178
+ object result_timezone
179
179
int year, month, day, minute, hour, second, weekday, julian
180
180
int week_of_year, week_of_year_start, parse_code, ordinal
181
181
int iso_week, iso_year
@@ -184,9 +184,6 @@ def array_strptime(
184
184
bint is_raise = errors== " raise"
185
185
bint is_ignore = errors== " ignore"
186
186
bint is_coerce = errors== " coerce"
187
- bint found_naive = False
188
- bint found_tz = False
189
- tzinfo tz_out = None
190
187
bint iso_format = format_is_iso(fmt)
191
188
NPY_DATETIMEUNIT out_bestunit
192
189
int out_local = 0 , out_tzoffset = 0
@@ -262,7 +259,7 @@ def array_strptime(
262
259
263
260
result = np.empty(n, dtype = " M8[ns]" )
264
261
iresult = result.view(" i8" )
265
- result_timezone = np.empty(n, dtype = " object " )
262
+ result_timezone = None
266
263
267
264
dts.us = dts.ps = dts.as = 0
268
265
@@ -277,30 +274,21 @@ def array_strptime(
277
274
iresult[i] = NPY_NAT
278
275
continue
279
276
elif PyDateTime_Check(val):
280
- if val.tzinfo is not None :
281
- found_tz = True
282
- else :
283
- found_naive = True
284
- tz_out = convert_timezone(
285
- val.tzinfo,
286
- tz_out,
287
- found_naive,
288
- found_tz,
289
- utc,
290
- )
291
- if isinstance (val, _Timestamp):
292
- iresult[i] = val.tz_localize(None ).as_unit(" ns" )._value
293
- else :
294
- iresult[i] = pydatetime_to_dt64(val.replace(tzinfo = None ), & dts)
295
- check_dts_bounds(& dts)
296
- result_timezone[i] = val.tzinfo
277
+ iresult[i] = parse_pydatetime(val, & dts, True )
278
+ check_dts_bounds(& dts)
279
+ if result_timezone is None :
280
+ result_timezone = val.tzinfo
281
+ elif result_timezone != val.tzinfo and not utc:
282
+ raise ValueError (" Can't parse mixed timezones with utc=False" )
297
283
continue
298
284
elif PyDate_Check(val):
299
285
iresult[i] = pydate_to_dt64(val, & dts)
300
286
check_dts_bounds(& dts)
301
287
continue
302
288
elif is_datetime64_object(val):
303
289
iresult[i] = get_datetime64_nanos(val, NPY_FR_ns)
290
+ if result_timezone is not None and not utc:
291
+ raise ValueError (" Can't parse mixed timezones with utc=False" )
304
292
continue
305
293
elif (
306
294
(is_integer_object(val) or is_float_object(val))
@@ -330,10 +318,12 @@ def array_strptime(
330
318
# since we store the total_seconds of
331
319
# dateutil.tz.tzoffset objects
332
320
tz = timezone(timedelta(minutes = out_tzoffset))
333
- result_timezone[i] = tz
321
+ if result_timezone is None :
322
+ result_timezone = tz
323
+ elif result_timezone != tz and not utc:
324
+ raise ValueError (" Can't parse mixed timezones with utc=False" )
334
325
out_local = 0
335
- out_tzoffset = 0
336
- iresult[i] = value
326
+ iresult[i] = value - < int64_t> out_tzoffset * 60 * 1 _000_000_000
337
327
check_dts_bounds(& dts)
338
328
continue
339
329
@@ -464,8 +454,9 @@ def array_strptime(
464
454
week_of_year_start = 0
465
455
elif parse_code == 17 :
466
456
tz = pytz.timezone(found_dict[" Z" ])
457
+ out_tzoffset = 0
467
458
elif parse_code == 19 :
468
- tz = parse_timezone_directive(found_dict[" z" ])
459
+ tz = parse_timezone_directive(found_dict[" z" ], & out_tzoffset )
469
460
elif parse_code == 20 :
470
461
iso_year = int (found_dict[" G" ])
471
462
elif parse_code == 21 :
@@ -512,11 +503,16 @@ def array_strptime(
512
503
dts.us = us
513
504
dts.ps = ns * 1000
514
505
515
- iresult[i] = npy_datetimestruct_to_datetime(NPY_FR_ns, & dts)
506
+ if result_timezone is None :
507
+ result_timezone = tz
508
+ elif result_timezone != tz and not utc:
509
+ raise ValueError (" Can't parse mixed timezones with utc=False" )
510
+ iresult[i] = (
511
+ npy_datetimestruct_to_datetime(NPY_FR_ns, & dts)
512
+ - < int64_t> out_tzoffset* 60 * 1 _000_000_000
513
+ )
516
514
check_dts_bounds(& dts)
517
515
518
- result_timezone[i] = tz
519
-
520
516
except (ValueError , OutOfBoundsDatetime) as ex:
521
517
ex.args = (
522
518
f" {str(ex)}, at position {i}. You might want to try:\n "
@@ -532,9 +528,8 @@ def array_strptime(
532
528
continue
533
529
elif is_raise:
534
530
raise
535
- return values, []
536
-
537
- return result, result_timezone.base
531
+ return values, None
532
+ return result, result_timezone
538
533
539
534
540
535
class TimeRE (_TimeRE ):
@@ -657,7 +652,7 @@ cdef (int, int) _calc_julian_from_V(int iso_year, int iso_week, int iso_weekday)
657
652
return iso_year, ordinal
658
653
659
654
660
- cdef tzinfo parse_timezone_directive(str z):
655
+ cdef tzinfo parse_timezone_directive(str z, int * offset_minutes ):
661
656
"""
662
657
Parse the '%z ' directive and return a datetime.timezone object.
663
658
@@ -701,4 +696,5 @@ cdef tzinfo parse_timezone_directive(str z):
701
696
total_minutes = ((hours * 60 ) + minutes + (seconds // 60 ) +
702
697
(microseconds // 60 _000_000))
703
698
total_minutes = - total_minutes if z.startswith(" -" ) else total_minutes
699
+ offset_minutes[0 ] = total_minutes
704
700
return timezone(timedelta(minutes = total_minutes))
0 commit comments