Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit bd88fa0

Browse files
floura-angelmroeschke
andauthored
BUG: honor ambiguous/nonexistent for tz-aware endpoints in date_range (#62493)
Co-authored-by: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com>
1 parent 7d7ee41 commit bd88fa0

File tree

3 files changed

+34
-7
lines changed

3 files changed

+34
-7
lines changed

‎doc/source/whatsnew/v3.0.0.rst‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,8 @@ Timezones
981981
^^^^^^^^^
982982
- Bug in :meth:`DatetimeIndex.union`, :meth:`DatetimeIndex.intersection`, and :meth:`DatetimeIndex.symmetric_difference` changing timezone to UTC when merging two DatetimeIndex objects with the same timezone but different units (:issue:`60080`)
983983
- Bug in :meth:`Series.dt.tz_localize` with a timezone-aware :class:`ArrowDtype` incorrectly converting to UTC when ``tz=None`` (:issue:`61780`)
984-
-
984+
- Fixed bug in :func:`date_range` where tz-aware endpoints with calendar offsets (e.g. ``"MS"``) failed on DST fall-back. These now respect ``ambiguous``/ ``nonexistent``. (:issue:`52908`)
985+
985986

986987
Numeric
987988
^^^^^^^

‎pandas/core/arrays/datetimes.py‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -456,13 +456,14 @@ def _generate_range(
456456
end = _maybe_localize_point(end, freq, tz, ambiguous, nonexistent)
457457

458458
if freq is not None:
459-
# We break Day arithmetic (fixed 24 hour) here and opt for
460-
# Day to mean calendar day (23/24/25 hour). Therefore, strip
461-
# tz info from start and day to avoid DST arithmetic
462-
if isinstance(freq, Day):
463-
if start is not None:
459+
# Offset handling:
460+
# Ticks (fixed-duration like hours/minutes): keep tz; do absolute-time math.
461+
# Other calendar offsets: drop tz; do naive wall time; localize once later
462+
# so `ambiguous`/`nonexistent` are applied correctly.
463+
if not isinstance(freq, Tick):
464+
if start is not None and start.tz is not None:
464465
start = start.tz_localize(None)
465-
if end is not None:
466+
if end is not Noneandend.tzisnotNone:
466467
end = end.tz_localize(None)
467468

468469
if isinstance(freq, (Tick, Day)):

‎pandas/tests/indexes/datetimes/test_date_range.py‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,3 +1740,28 @@ def test_date_range_negative_freq_year_end_inbounds(self, unit):
17401740
freq="-1YE",
17411741
)
17421742
tm.assert_index_equal(rng, exp)
1743+
1744+
def test_date_range_tzaware_endpoints_accept_ambiguous(self):
1745+
# https://github.com/pandas-dev/pandas/issues/52908
1746+
start = Timestamp("1916年08月01日", tz="Europe/Oslo")
1747+
end = Timestamp("1916年12月01日", tz="Europe/Oslo")
1748+
res = date_range(start, end, freq="MS", ambiguous=True)
1749+
exp = date_range(
1750+
"1916年08月01日", "1916年12月01日", freq="MS", tz="Europe/Oslo", ambiguous=True
1751+
)
1752+
tm.assert_index_equal(res, exp)
1753+
1754+
def test_date_range_tzaware_endpoints_accept_nonexistent(self):
1755+
# Europe/London spring-forward: 2015年03月29日 01:30 does not exist.
1756+
tz = "Europe/London"
1757+
start = Timestamp("2015年03月28日 01:30", tz=tz)
1758+
end = Timestamp("2015年03月30日 01:30", tz=tz)
1759+
1760+
result = date_range(start, end, freq="D", nonexistent="shift_forward")
1761+
1762+
# Build expected by generating naive daily times, then tz_localize so
1763+
# the nonexistent handling is applied during localization.
1764+
expected = date_range(
1765+
"2015年03月28日 01:30", "2015年03月30日 01:30", freq="D"
1766+
).tz_localize(tz, nonexistent="shift_forward")
1767+
tm.assert_index_equal(result, expected)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /