Skip to content

Commit 56afb9b

Browse files
author
MarcoGorelli
committed
factor out parse_pydatetime
1 parent d1ecf63 commit 56afb9b

File tree

3 files changed

+114
-28
lines changed

3 files changed

+114
-28
lines changed

pandas/_libs/tslib.pyx

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,16 @@ from pandas._libs.tslibs.conversion cimport (
5151
cast_from_unit,
5252
convert_datetime_to_tsobject,
5353
get_datetime64_nanos,
54+
parse_pydatetime,
5455
precision_from_unit,
56+
validate_tzout,
5557
)
5658
from pandas._libs.tslibs.nattype cimport (
5759
NPY_NAT,
5860
c_NaT as NaT,
5961
c_nat_strings as nat_strings,
6062
)
6163
from pandas._libs.tslibs.timestamps cimport _Timestamp
62-
from pandas._libs.tslibs.timezones cimport tz_compare
6364

6465
from pandas._libs.tslibs import (
6566
Resolution,
@@ -525,35 +526,16 @@ cpdef array_to_datetime(
525526
seen_datetime = True
526527
if val.tzinfo is not None:
527528
found_tz = True
528-
if utc_convert:
529-
_ts = convert_datetime_to_tsobject(val, None)
530-
_ts.ensure_reso(NPY_FR_ns)
531-
iresult[i] = _ts.value
532-
elif found_naive:
533-
raise ValueError('Tz-aware datetime.datetime '
534-
'cannot be converted to '
535-
'datetime64 unless utc=True')
536-
elif tz_out is not None and not tz_compare(tz_out, val.tzinfo):
537-
raise ValueError('Tz-aware datetime.datetime '
538-
'cannot be converted to '
539-
'datetime64 unless utc=True')
540-
else:
541-
found_tz = True
542-
tz_out = val.tzinfo
543-
_ts = convert_datetime_to_tsobject(val, None)
544-
_ts.ensure_reso(NPY_FR_ns)
545-
iresult[i] = _ts.value
546-
547529
else:
548530
found_naive = True
549-
if found_tz and not utc_convert:
550-
raise ValueError('Cannot mix tz-aware with '
551-
'tz-naive values')
552-
if isinstance(val, _Timestamp):
553-
iresult[i] = val.as_unit("ns").value
554-
else:
555-
iresult[i] = pydatetime_to_dt64(val, &dts)
556-
check_dts_bounds(&dts)
531+
tz_out = validate_tzout(
532+
val.tzinfo,
533+
tz_out,
534+
found_naive,
535+
found_tz,
536+
utc_convert,
537+
)
538+
result[i] = parse_pydatetime(val, &dts, utc_convert)
557539

558540
elif PyDate_Check(val):
559541
seen_datetime = True

pandas/_libs/tslibs/conversion.pxd

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ from pandas._libs.tslibs.np_datetime cimport (
1212
NPY_DATETIMEUNIT,
1313
npy_datetimestruct,
1414
)
15+
from pandas._libs.tslibs.timestamps cimport _Timestamp
16+
from pandas._libs.tslibs.timezones cimport tz_compare
1517

1618

1719
cdef class _TSObject:
@@ -40,3 +42,17 @@ cdef int64_t cast_from_unit(object ts, str unit) except? -1
4042
cpdef (int64_t, int) precision_from_unit(str unit)
4143

4244
cdef maybe_localize_tso(_TSObject obj, tzinfo tz, NPY_DATETIMEUNIT reso)
45+
46+
cdef tzinfo validate_tzout(
47+
tzinfo tz_in,
48+
tzinfo tz_out,
49+
bint found_naive,
50+
bint found_tz,
51+
bint utc_convert,
52+
)
53+
54+
cdef int64_t parse_pydatetime(
55+
object val,
56+
npy_datetimestruct *dts,
57+
bint utc_convert,
58+
) except -1

pandas/_libs/tslibs/conversion.pyx

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ from pandas._libs.tslibs.np_datetime cimport (
4141
npy_datetimestruct,
4242
npy_datetimestruct_to_datetime,
4343
pandas_datetime_to_datetimestruct,
44+
pydatetime_to_dt64,
4445
pydatetime_to_dtstruct,
4546
string_to_dts,
4647
)
@@ -642,3 +643,90 @@ cpdef inline datetime localize_pydatetime(datetime dt, tzinfo tz):
642643
elif isinstance(dt, ABCTimestamp):
643644
return dt.tz_localize(tz)
644645
return _localize_pydatetime(dt, tz)
646+
647+
648+
cdef tzinfo validate_tzout(
649+
tzinfo tz_in,
650+
tzinfo tz_out,
651+
bint found_naive,
652+
bint found_tz,
653+
bint utc_convert,
654+
):
655+
"""
656+
Validate that ``tz_out`` and ``tz_in`` are compatible.
657+
658+
Parameters
659+
----------
660+
tz_in : tzinfo
661+
Timezone info of element being processed.
662+
tz_out : tzinfo
663+
Timezone info of output.
664+
found_naive : bool
665+
Whether a timezone-naive element has been found so far.
666+
found_tz : bool
667+
Whether a timezone-aware element has been found so far.
668+
utc_convert : bool
669+
Whether to convert/localize to UTC.
670+
671+
Returns
672+
-------
673+
tz_info
674+
Timezone info of output.
675+
676+
Raises
677+
------
678+
ValueError
679+
If ``tz_out`` and ``tz_in`` aren't compatible.
680+
"""
681+
if tz_in is not None:
682+
if utc_convert:
683+
pass
684+
elif found_naive:
685+
raise ValueError('Tz-aware datetime.datetime '
686+
'cannot be converted to '
687+
'datetime64 unless utc=True')
688+
elif tz_out is not None and not tz_compare(tz_out, tz_in):
689+
raise ValueError('Tz-aware datetime.datetime '
690+
'cannot be converted to '
691+
'datetime64 unless utc=True')
692+
else:
693+
tz_out = tz_in
694+
else:
695+
if found_tz and not utc_convert:
696+
raise ValueError('Cannot mix tz-aware with '
697+
'tz-naive values')
698+
return tz_out
699+
700+
cdef int64_t parse_pydatetime(
701+
object val,
702+
npy_datetimestruct *dts,
703+
bint utc_convert,
704+
) except -1:
705+
"""
706+
Convert pydatetime to datetime64.
707+
708+
Parameters
709+
----------
710+
val
711+
Element being processed.
712+
dts : *npy_datetimestruct
713+
Needed to use in pydatetime_to_dt64, which writes to it.
714+
utc_convert : bool
715+
Whether to convert/localize to UTC.
716+
"""
717+
if val.tzinfo is not None:
718+
if utc_convert:
719+
_ts = convert_datetime_to_tsobject(val, None)
720+
_ts.ensure_reso(NPY_FR_ns)
721+
result = _ts.value
722+
else:
723+
_ts = convert_datetime_to_tsobject(val, None)
724+
_ts.ensure_reso(NPY_FR_ns)
725+
result = _ts.value
726+
else:
727+
if isinstance(val, _Timestamp):
728+
result = val.as_unit("ns").value
729+
else:
730+
result = pydatetime_to_dt64(val, dts)
731+
check_dts_bounds(dts)
732+
return result

0 commit comments

Comments
 (0)