Skip to content

Commit 77278ba

Browse files
gabrielreidmroeschke
authored andcommitted
BUG: date_range issue with millisecond resolution (#24129)
Fixes #24110, by avoid floating-point rounding issues with millisecond resolution or higher timestamps when creating a date range.
1 parent fb7dbe0 commit 77278ba

File tree

3 files changed

+18
-1
lines changed

3 files changed

+18
-1
lines changed

doc/source/whatsnew/v0.24.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,7 @@ Datetimelike
12851285
- Bug in :class:`DatetimeIndex` where calling ``np.array(dtindex, dtype=object)`` would incorrectly return an array of ``long`` objects (:issue:`23524`)
12861286
- Bug in :class:`Index` where passing a timezone-aware :class:`DatetimeIndex` and `dtype=object` would incorrectly raise a ``ValueError`` (:issue:`23524`)
12871287
- Bug in :class:`Index` where calling ``np.array(dtindex, dtype=object)`` on a timezone-naive :class:`DatetimeIndex` would return an array of ``datetime`` objects instead of :class:`Timestamp` objects, potentially losing nanosecond portions of the timestamps (:issue:`23524`)
1288+
- Bug in :func:`date_range` where using dates with millisecond resolution or higher could return incorrect values or the wrong number of values in the index (:issue:`24110`)
12881289

12891290
Timedelta
12901291
^^^^^^^^^

pandas/core/arrays/datetimes.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,12 @@ def _generate_range(cls, start, end, periods, freq, tz=None,
307307
end = end.tz_localize(tz).asm8
308308
else:
309309
# Create a linearly spaced date_range in local time
310-
arr = np.linspace(start.value, end.value, periods)
310+
# Nanosecond-granularity timestamps aren't always correctly
311+
# representable with doubles, so we limit the range that we
312+
# pass to np.linspace as much as possible
313+
arr = np.linspace(
314+
0, end.value - start.value,
315+
periods, dtype='int64') + start.value
311316
index = cls._simple_new(
312317
arr.astype('M8[ns]', copy=False), freq=None, tz=tz
313318
)

pandas/tests/indexes/datetimes/test_date_range.py

+11
Original file line numberDiff line numberDiff line change
@@ -769,3 +769,14 @@ def test_all_custom_freq(self, freq):
769769
msg = 'invalid custom frequency string: {freq}'
770770
with pytest.raises(ValueError, match=msg.format(freq=bad_freq)):
771771
bdate_range(START, END, freq=bad_freq)
772+
773+
@pytest.mark.parametrize('start_end', [
774+
('2018-01-01T00:00:01.000Z', '2018-01-03T00:00:01.000Z'),
775+
('2018-01-01T00:00:00.010Z', '2018-01-03T00:00:00.010Z'),
776+
('2001-01-01T00:00:00.010Z', '2001-01-03T00:00:00.010Z')])
777+
def test_range_with_millisecond_resolution(self, start_end):
778+
# https://github.com/pandas-dev/pandas/issues/24110
779+
start, end = start_end
780+
result = pd.date_range(start=start, end=end, periods=2, closed='left')
781+
expected = DatetimeIndex([start])
782+
tm.assert_index_equal(result, expected)

0 commit comments

Comments
 (0)