Skip to content

Commit 61cc22b

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

File tree

4 files changed

+26
-7
lines changed

4 files changed

+26
-7
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

+8-7
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ from tslibs.timezones cimport (is_utc, is_tzlocal, is_fixed_offset,
4646
treat_tz_as_pytz, get_dst_info)
4747
from tslibs.conversion cimport (tz_convert_single, _TSObject,
4848
convert_datetime_to_tsobject,
49-
get_datetime64_nanos)
49+
get_datetime64_nanos,
50+
tz_convert_utc_to_tzlocal)
5051
from tslibs.conversion import tz_convert_single
5152

5253
from tslibs.nattype import NaT, nat_strings, iNaT
@@ -144,12 +145,12 @@ def ints_to_pydatetime(ndarray[int64_t] arr, tz=None, freq=None,
144145
if value == NPY_NAT:
145146
result[i] = NaT
146147
else:
147-
dt64_to_dtstruct(value, &dts)
148-
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
148+
# Python datetime objects do not support nanosecond
149+
# resolution (yet, PEP 564). Need to compute new value
150+
# using the i8 representation.
151+
local_value = tz_convert_utc_to_tzlocal(value, tz)
152+
dt64_to_dtstruct(local_value, &dts)
153+
result[i] = func_create(value, dts, tz, freq)
153154
else:
154155
trans, deltas, typ = get_dst_info(tz)
155156

pandas/conftest.py

+7
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,10 @@ def compression_no_zip(request):
9393
except zip
9494
"""
9595
return request.param
96+
97+
98+
@pytest.fixture(scope='module')
99+
@pytest.mark.skipif(not pandas.compat.PY3)
100+
def datetime_tz_utc():
101+
from datetime import timezone
102+
return timezone.utc

pandas/tests/indexes/datetimes/test_timezones.py

+10
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,16 @@ def test_dti_union_aware(self):
949949
result = rng.union(rng2)
950950
assert result.tz.zone == 'UTC'
951951

952+
@pytest.mark.parametrize('tz', [None, 'UTC', "US/Central",
953+
dateutil.tz.tzoffset(None, -28800)])
954+
@pytest.mark.usefixtures("datetime_tz_utc")
955+
def test_iteration_preserves_nanoseconds(self, tz):
956+
# GH 19603
957+
index = DatetimeIndex(["2018-02-08 15:00:00.168456358",
958+
"2018-02-08 15:00:00.168456359"], tz=tz)
959+
for i, ts in enumerate(index):
960+
assert ts == index[i]
961+
952962

953963
class TestDateRange(object):
954964
"""Tests for date_range with timezones"""

0 commit comments

Comments
 (0)