Skip to content

Commit 4c27530

Browse files
committed
Add whatsnew, write test
1 parent 6b51d28 commit 4c27530

File tree

4 files changed

+63
-54
lines changed

4 files changed

+63
-54
lines changed

doc/source/whatsnew/v3.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ Datetimelike
500500
- Bug in :meth:`DatetimeIndex.is_year_start` and :meth:`DatetimeIndex.is_quarter_start` does not raise on Custom business days frequencies bigger then "1C" (:issue:`58664`)
501501
- Bug in :meth:`DatetimeIndex.is_year_start` and :meth:`DatetimeIndex.is_quarter_start` returning ``False`` on double-digit frequencies (:issue:`58523`)
502502
- Bug in :meth:`DatetimeIndex.union` when ``unit`` was non-nanosecond (:issue:`59036`)
503+
- Bug in :meth:`to_datetime` not respecting dayfirst if an uncommon date string was passed. (:issue:`58859`)
503504
- Bug in setting scalar values with mismatched resolution into arrays with non-nanosecond ``datetime64``, ``timedelta64`` or :class:`DatetimeTZDtype` incorrectly truncating those scalars (:issue:`56410`)
504505

505506
Timedelta

pandas/_libs/tslibs/conversion.pyx

+35-30
Original file line numberDiff line numberDiff line change
@@ -606,37 +606,42 @@ cdef _TSObject convert_str_to_tsobject(str ts, tzinfo tz,
606606
# equiv: datetime.today().replace(tzinfo=tz)
607607
return convert_datetime_to_tsobject(dt, tz, nanos=0, reso=NPY_FR_us)
608608
else:
609-
string_to_dts_failed = string_to_dts(
610-
ts, &dts, &out_bestunit, &out_local,
611-
&out_tzoffset, False
612-
)
613-
if not string_to_dts_failed and not dayfirst:
614-
reso = get_supported_reso(out_bestunit)
615-
check_dts_bounds(&dts, reso)
616-
obj = _TSObject()
617-
obj.dts = dts
618-
obj.creso = reso
619-
ival = npy_datetimestruct_to_datetime(reso, &dts)
620-
621-
if out_local == 1:
622-
obj.tzinfo = timezone(timedelta(minutes=out_tzoffset))
623-
obj.value = tz_localize_to_utc_single(
624-
ival, obj.tzinfo, ambiguous="raise", nonexistent=None, creso=reso
625-
)
626-
if tz is None:
627-
check_overflows(obj, reso)
628-
return obj
629-
_adjust_tsobject_tz_using_offset(obj, tz)
630-
return obj
631-
else:
632-
if tz is not None:
633-
# shift for _localize_tso
634-
ival = tz_localize_to_utc_single(
635-
ival, tz, ambiguous="raise", nonexistent=None, creso=reso
609+
if not dayfirst: # GH 58859
610+
string_to_dts_failed = string_to_dts(
611+
ts, &dts, &out_bestunit, &out_local,
612+
&out_tzoffset, False
613+
)
614+
if not string_to_dts_failed:
615+
reso = get_supported_reso(out_bestunit)
616+
check_dts_bounds(&dts, reso)
617+
obj = _TSObject()
618+
obj.dts = dts
619+
obj.creso = reso
620+
ival = npy_datetimestruct_to_datetime(reso, &dts)
621+
622+
if out_local == 1:
623+
obj.tzinfo = timezone(timedelta(minutes=out_tzoffset))
624+
obj.value = tz_localize_to_utc_single(
625+
ival,
626+
obj.tzinfo,
627+
ambiguous="raise",
628+
nonexistent=None,
629+
creso=reso,
636630
)
637-
obj.value = ival
638-
maybe_localize_tso(obj, tz, obj.creso)
639-
return obj
631+
if tz is None:
632+
check_overflows(obj, reso)
633+
return obj
634+
_adjust_tsobject_tz_using_offset(obj, tz)
635+
return obj
636+
else:
637+
if tz is not None:
638+
# shift for _localize_tso
639+
ival = tz_localize_to_utc_single(
640+
ival, tz, ambiguous="raise", nonexistent=None, creso=reso
641+
)
642+
obj.value = ival
643+
maybe_localize_tso(obj, tz, obj.creso)
644+
return obj
640645

641646
dt = parse_datetime_string(
642647
ts,

pandas/_libs/tslibs/parsing.pyx

+25-24
Original file line numberDiff line numberDiff line change
@@ -377,32 +377,33 @@ def parse_datetime_string_with_reso(
377377
raise ValueError(f'Given date string "{date_string}" not likely a datetime')
378378

379379
# Try iso8601 first, as it handles nanoseconds
380-
string_to_dts_failed = string_to_dts(
381-
date_string, &dts, &out_bestunit, &out_local,
382-
&out_tzoffset, False
383-
)
384-
if not string_to_dts_failed:
385-
# Match Timestamp and drop picoseconds, femtoseconds, attoseconds
386-
# The new resolution will just be nano
387-
# GH#50417
388-
if out_bestunit in _timestamp_units:
389-
out_bestunit = NPY_DATETIMEUNIT.NPY_FR_ns
390-
391-
if out_bestunit == NPY_DATETIMEUNIT.NPY_FR_ns:
392-
# TODO: avoid circular import
393-
from pandas import Timestamp
394-
parsed = Timestamp(date_string)
395-
else:
396-
if out_local:
397-
tz = timezone(timedelta(minutes=out_tzoffset))
380+
if not dayfirst: # GH 58859
381+
string_to_dts_failed = string_to_dts(
382+
date_string, &dts, &out_bestunit, &out_local,
383+
&out_tzoffset, False
384+
)
385+
if not string_to_dts_failed:
386+
# Match Timestamp and drop picoseconds, femtoseconds, attoseconds
387+
# The new resolution will just be nano
388+
# GH#50417
389+
if out_bestunit in _timestamp_units:
390+
out_bestunit = NPY_DATETIMEUNIT.NPY_FR_ns
391+
392+
if out_bestunit == NPY_DATETIMEUNIT.NPY_FR_ns:
393+
# TODO: avoid circular import
394+
from pandas import Timestamp
395+
parsed = Timestamp(date_string)
398396
else:
399-
tz = None
400-
parsed = datetime_new(
401-
dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.us, tz
402-
)
397+
if out_local:
398+
tz = timezone(timedelta(minutes=out_tzoffset))
399+
else:
400+
tz = None
401+
parsed = datetime_new(
402+
dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.us, tz
403+
)
403404

404-
reso = npy_unit_to_attrname[out_bestunit]
405-
return parsed, reso
405+
reso = npy_unit_to_attrname[out_bestunit]
406+
return parsed, reso
406407

407408
parsed = _parse_delimited_date(date_string, dayfirst, &out_bestunit)
408409
if parsed is not None:

pandas/tests/tools/test_to_datetime.py

+2
Original file line numberDiff line numberDiff line change
@@ -2988,6 +2988,8 @@ def test_parsers_nat(self):
29882988
("20/12/21", True, False, datetime(2021, 12, 20)),
29892989
("20/12/21", False, True, datetime(2020, 12, 21)),
29902990
("20/12/21", True, True, datetime(2020, 12, 21)),
2991+
# GH 58859
2992+
("20201012", True, False, datetime(2020, 12, 10)),
29912993
],
29922994
)
29932995
def test_parsers_dayfirst_yearfirst(

0 commit comments

Comments
 (0)