Skip to content

Commit 7a34bcb

Browse files
committed
Added tests and fix for DatetimeIndex
1 parent 6ab2c06 commit 7a34bcb

File tree

2 files changed

+52
-27
lines changed

2 files changed

+52
-27
lines changed

pandas/core/indexes/datetimelike.py

+18-7
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,29 @@ def _round(self, freq, rounder):
9595
unit = to_offset(freq).nanos
9696
# round the local times
9797
values = _ensure_datetimelike_to_i8(self)
98-
if unit < 1000 and unit % 1000 != 0:
98+
99+
if unit < 1000:
99100
# for nano rounding, work with the last 6 digits separately
100101
# due to float precision
101102
buff = 1000000
102103
result = (buff * (values // buff) + unit *
103-
(rounder((values % buff) / float(unit))).astype('i8'))
104-
elif unit >= 1000 and unit % 1000 != 0:
105-
msg = 'Precision will be lost using frequency: {}'
106-
warnings.warn(msg.format(freq))
107-
result = (unit * rounder(values / float(unit)).astype('i8'))
104+
(rounder((values % buff) * (1 / float(unit))))
105+
.astype('i8'))
108106
else:
109-
result = (unit * rounder(values / float(unit)).astype('i8'))
107+
if unit % 1000 != 0:
108+
msg = 'Precision will be lost using frequency: {}'
109+
warnings.warn(msg.format(freq))
110+
111+
# GH19206
112+
# to deal with round-off when unit is large
113+
if unit >= 1e9:
114+
divisor = 10 ** int(np.log10(unit / 1e7))
115+
else:
116+
divisor = 10
117+
118+
result = (unit * rounder((values * (divisor / float(unit))) /
119+
divisor).astype('i8'))
120+
110121
result = self._maybe_mask_results(result, fill_value=NaT)
111122

112123
attribs = self._get_attributes_dict()

pandas/tests/indexes/datetimes/test_ops.py

+34-20
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,40 @@ def test_numpy_minmax(self):
144144
tm.assert_raises_regex(
145145
ValueError, errmsg, np.argmax, dr, out=0)
146146

147-
def test_round(self):
147+
@pytest.mark.parametrize('test_input, rounder, freq, expected', [
148+
# GH 14440 & 15578
149+
('2016-10-17 12:00:00.0015', 'round', 'ms',
150+
'2016-10-17 12:00:00.002000'),
151+
('2016-10-17 12:00:00.0015', 'round', 'us',
152+
'2016-10-17 12:00:00.0015'),
153+
('2016-10-17 12:00:00.0015', 'round', 'ns',
154+
'2016-10-17 12:00:00.0015'),
155+
('2016-10-17 12:00:00.00149', 'round', 'ms',
156+
'2016-10-17 12:00:00.001000'),
157+
('2016-10-17 12:00:00.001501031', 'round', '10ns',
158+
'2016-10-17 12:00:00.001501030'),
159+
# GH 19206 - times far in the future and past rounding incorrectly
160+
('2117-01-01 00:00:45', 'floor', '15s', '2117-01-01 00:00:45'),
161+
('2117-01-01 00:00:45', 'ceil', '15s', '2117-01-01 00:00:45'),
162+
('2117-01-01 00:00:45.000000012', 'floor', '10ns',
163+
'2117-01-01 00:00:45.000000010'),
164+
('1823-01-01 00:00:01', 'floor', '1s', '1823-01-01 00:00:01'),
165+
('1823-01-01 00:00:01', 'ceil', '1s', '1823-01-01 00:00:01'),
166+
('1823-01-01 00:00:01.000000012', 'floor', '10ns',
167+
'1823-01-01 00:00:01.000000010'),
168+
('1823-01-01 00:00:01.000000012', 'ceil', '10ns',
169+
'1823-01-01 00:00:01.000000020')
170+
])
171+
# @pytest.mark.parametrize('tz', tz)
172+
def test_round_ops(self, test_input, rounder, freq, expected):
173+
for tz in self.tz:
174+
index = pd.DatetimeIndex([test_input], tz=tz)
175+
func = getattr(index, rounder)
176+
result = func(freq)
177+
expect = pd.DatetimeIndex([expected], tz=tz)
178+
tm.assert_index_equal(result, expect)
179+
180+
def test_round_raises(self):
148181
for tz in self.tz:
149182
rng = pd.date_range(start='2016-01-01', periods=5,
150183
freq='30Min', tz=tz)
@@ -172,25 +205,6 @@ def test_round(self):
172205
tm.assert_raises_regex(ValueError, msg, rng.round, freq='M')
173206
tm.assert_raises_regex(ValueError, msg, elt.round, freq='M')
174207

175-
# GH 14440 & 15578
176-
index = pd.DatetimeIndex(['2016-10-17 12:00:00.0015'], tz=tz)
177-
result = index.round('ms')
178-
expected = pd.DatetimeIndex(['2016-10-17 12:00:00.002000'], tz=tz)
179-
tm.assert_index_equal(result, expected)
180-
181-
for freq in ['us', 'ns']:
182-
tm.assert_index_equal(index, index.round(freq))
183-
184-
index = pd.DatetimeIndex(['2016-10-17 12:00:00.00149'], tz=tz)
185-
result = index.round('ms')
186-
expected = pd.DatetimeIndex(['2016-10-17 12:00:00.001000'], tz=tz)
187-
tm.assert_index_equal(result, expected)
188-
189-
index = pd.DatetimeIndex(['2016-10-17 12:00:00.001501031'])
190-
result = index.round('10ns')
191-
expected = pd.DatetimeIndex(['2016-10-17 12:00:00.001501030'])
192-
tm.assert_index_equal(result, expected)
193-
194208
with tm.assert_produces_warning():
195209
ts = '2016-10-17 12:00:00.001501031'
196210
pd.DatetimeIndex([ts]).round('1010ns')

0 commit comments

Comments
 (0)