Skip to content

Commit 1df622b

Browse files
committed
Bug: Do not round DatetimeIndex nanosecond precision when iterating
Fix the issue within fix_offsets add addtional dateutil test
1 parent cd484cc commit 1df622b

File tree

3 files changed

+21
-5
lines changed

3 files changed

+21
-5
lines changed

doc/source/whatsnew/v0.23.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,7 @@ Timezones
728728
- Bug in :func:`DatetimeIndex.insert` where inserting ``NaT`` into a timezone-aware index incorrectly raised (:issue:`16357`)
729729
- Bug in the :class:`DataFrame` constructor, where tz-aware Datetimeindex and a given column name will result in an empty ``DataFrame`` (:issue:`19157`)
730730
- Bug in :func:`Timestamp.tz_localize` where localizing a timestamp near the minimum or maximum valid values could overflow and return a timestamp with an incorrect nanosecond value (:issue:`12677`)
731+
- Bug when iterating over :class:`DatetimeIndex` that was localized with fixed timezone offset that rounded nanosecond precision to microseconds (:issue:`19603`)
731732

732733
Offsets
733734
^^^^^^^

pandas/_libs/tslib.pyx

+6-4
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,12 @@ def ints_to_pydatetime(ndarray[int64_t] arr, tz=None, freq=None,
146146
else:
147147
dt64_to_dtstruct(value, &dts)
148148
dt = create_datetime_from_ts(value, dts, tz, freq)
149-
dt = dt + tz.utcoffset(dt)
150-
if box:
151-
dt = Timestamp(dt)
152-
result[i] = dt
149+
# Python datetime objects do not support nanosecond
150+
# resolution (yet, PEP 564). Need to compute new value
151+
# using the i8 representation.
152+
offset = int(tz.utcoffset(dt).total_seconds()) * 1000000000
153+
dt64_to_dtstruct(value + offset, &dts)
154+
result[i] = func_create(value, dts, tz, freq)
153155
else:
154156
trans, deltas, typ = get_dst_info(tz)
155157

pandas/tests/indexes/datetimes/test_datetime.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,18 @@
77
import dateutil
88
import pandas as pd
99
import pandas.util.testing as tm
10-
from pandas.compat import lrange
10+
from pandas.compat import lrange, PY3
1111
from pandas import (DatetimeIndex, Index, date_range, DataFrame,
1212
Timestamp, offsets)
1313

1414
from pandas.util.testing import assert_almost_equal
1515

16+
if PY3:
17+
from datetime import timezone
18+
dt_UTC = timezone.utc
19+
else:
20+
dt_UTC = None
21+
1622
randn = np.random.randn
1723

1824

@@ -258,6 +264,13 @@ def test_iteration_preserves_tz(self):
258264
assert result._repr_base == expected._repr_base
259265
assert result == expected
260266

267+
@pytest.mark.parametrize('tz', [None, 'UTC', "US/Central", dt_UTC,
268+
dateutil.tz.tzoffset(None, -28800)])
269+
def test_iteration_preserves_nanoseconds(self, tz):
270+
# GH 19603
271+
index = pd.DatetimeIndex(["2018-02-08 15:00:00.168456358"], tz=tz)
272+
assert list(index)[0] == index[0]
273+
261274
def test_misc_coverage(self):
262275
rng = date_range('1/1/2000', periods=5)
263276
result = rng.groupby(rng.day)

0 commit comments

Comments
 (0)