Skip to content

Commit 88eefc1

Browse files
committed
API: Issue real warning in to_pydatetime
1 parent 57e9bb9 commit 88eefc1

File tree

4 files changed

+51
-12
lines changed

4 files changed

+51
-12
lines changed

doc/source/whatsnew/v0.19.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ API changes
436436
~~~~~~~~~~~
437437

438438

439+
- ``Timestamp.to_pydatetime`` will issue a ``UserWarning`` when ``warn=True``, and the instance has a non-zero number of nanoseconds (:issue:`14101`)
439440
- ``Panel.to_sparse`` will raise a ``NotImplementedError`` exception when called (:issue:`13778`)
440441
- ``Index.reshape`` will raise a ``NotImplementedError`` exception when called (:issue:`12882`)
441442
- Non-convertible dates in an excel date column will be returned without conversion and the column will be ``object`` dtype, rather than raising an exception (:issue:`10001`)

pandas/tseries/tests/test_offsets.py

+26-4
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,19 @@ def _check_offsetfunc_works(self, offset, funcname, dt, expected,
261261
self.assertTrue(isinstance(result, Timestamp))
262262
self.assertEqual(result, expected)
263263

264-
# test nano second is preserved
265-
result = func(Timestamp(dt) + Nano(5))
264+
# see gh-14101
265+
exp_warning = None
266+
ts = Timestamp(dt) + Nano(5)
267+
268+
if (offset_s.__class__.__name__ == 'DateOffset' and
269+
(funcname == 'apply' or normalize) and
270+
ts.nanosecond > 0):
271+
exp_warning = UserWarning
272+
273+
# test nanosecond is preserved
274+
with tm.assert_produces_warning(exp_warning,
275+
check_stacklevel=False):
276+
result = func(ts)
266277
self.assertTrue(isinstance(result, Timestamp))
267278
if normalize is False:
268279
self.assertEqual(result, expected + Nano(5))
@@ -289,8 +300,19 @@ def _check_offsetfunc_works(self, offset, funcname, dt, expected,
289300
self.assertTrue(isinstance(result, Timestamp))
290301
self.assertEqual(result, expected_localize)
291302

292-
# test nano second is preserved
293-
result = func(Timestamp(dt, tz=tz) + Nano(5))
303+
# see gh-14101
304+
exp_warning = None
305+
ts = Timestamp(dt, tz=tz) + Nano(5)
306+
307+
if (offset_s.__class__.__name__ == 'DateOffset' and
308+
(funcname == 'apply' or normalize) and
309+
ts.nanosecond > 0):
310+
exp_warning = UserWarning
311+
312+
# test nanosecond is preserved
313+
with tm.assert_produces_warning(exp_warning,
314+
check_stacklevel=False):
315+
result = func(ts)
294316
self.assertTrue(isinstance(result, Timestamp))
295317
if normalize is False:
296318
self.assertEqual(result, expected_localize + Nano(5))

pandas/tseries/tests/test_tslib.py

+21-6
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,17 @@ def test_max_valid(self):
4747
def test_to_datetime_bijective(self):
4848
# Ensure that converting to datetime and back only loses precision
4949
# by going from nanoseconds to microseconds.
50-
self.assertEqual(
51-
Timestamp(Timestamp.max.to_pydatetime()).value / 1000,
52-
Timestamp.max.value / 1000)
53-
self.assertEqual(
54-
Timestamp(Timestamp.min.to_pydatetime()).value / 1000,
55-
Timestamp.min.value / 1000)
50+
exp_warning = None if Timestamp.max.nanosecond == 0 else UserWarning
51+
with tm.assert_produces_warning(exp_warning, check_stacklevel=False):
52+
self.assertEqual(
53+
Timestamp(Timestamp.max.to_pydatetime()).value / 1000,
54+
Timestamp.max.value / 1000)
55+
56+
exp_warning = None if Timestamp.min.nanosecond == 0 else UserWarning
57+
with tm.assert_produces_warning(exp_warning, check_stacklevel=False):
58+
self.assertEqual(
59+
Timestamp(Timestamp.min.to_pydatetime()).value / 1000,
60+
Timestamp.min.value / 1000)
5661

5762

5863
class TestTimestamp(tm.TestCase):
@@ -626,6 +631,16 @@ def to_datetime_depr(self):
626631
result = ts.to_datetime()
627632
self.assertEqual(result, expected)
628633

634+
def to_pydatetime_nonzero_nano(self):
635+
ts = Timestamp('2011-01-01 9:00:00.123456789')
636+
637+
# Warn the user of data loss (nanoseconds).
638+
with tm.assert_produces_warning(UserWarning,
639+
check_stacklevel=False):
640+
expected = datetime.datetime(2011, 1, 1, 9, 0, 0, 123456)
641+
result = ts.to_pydatetime()
642+
self.assertEqual(result, expected)
643+
629644

630645
class TestDatetimeParsingWrappers(tm.TestCase):
631646
def test_does_not_convert_mixed_integer(self):

pandas/tslib.pyx

+3-2
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ cdef class _Timestamp(datetime):
10341034

10351035
cdef bint _compare_outside_nanorange(_Timestamp self, datetime other,
10361036
int op) except -1:
1037-
cdef datetime dtval = self.to_pydatetime(warn=False)
1037+
cdef datetime dtval = self.to_pydatetime()
10381038

10391039
self._assert_tzawareness_compat(other)
10401040

@@ -1084,7 +1084,8 @@ cdef class _Timestamp(datetime):
10841084
_TSObject ts
10851085

10861086
if self.nanosecond != 0 and warn:
1087-
print 'Warning: discarding nonzero nanoseconds'
1087+
warnings.warn("Discarding nonzero nanoseconds in conversion",
1088+
UserWarning, stacklevel=2)
10881089
ts = convert_to_tsobject(self, self.tzinfo, None, 0, 0)
10891090
dts = ts.dts
10901091
return datetime(dts.year, dts.month, dts.day,

0 commit comments

Comments
 (0)