Skip to content

Commit 0976d0c

Browse files
jbrockmendelNo-Stream
authored andcommitted
have _NaT subclass datetime directly (pandas-dev#17793)
1 parent a3498f1 commit 0976d0c

File tree

1 file changed

+69
-25
lines changed

1 file changed

+69
-25
lines changed

pandas/_libs/tslib.pyx

+69-25
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ from util cimport (is_integer_object, is_float_object, is_datetime64_object,
3030
is_timedelta64_object, INT64_MAX)
3131
cimport util
3232

33-
from cpython.datetime cimport PyTZInfo_Check
33+
from cpython.datetime cimport PyDelta_Check, PyTZInfo_Check
3434
# this is our datetime.pxd
3535
from datetime cimport (
3636
pandas_datetimestruct,
@@ -50,7 +50,6 @@ from datetime cimport (
5050
check_dts_bounds,
5151
PANDAS_FR_ns,
5252
PyDateTime_Check, PyDate_Check,
53-
PyDelta_Check, # PyDelta_Check(x) --> isinstance(x, timedelta)
5453
PyDateTime_IMPORT,
5554
timedelta, datetime
5655
)
@@ -840,6 +839,7 @@ class NaTType(_NaT):
840839

841840
base = _NaT.__new__(cls, 1, 1, 1)
842841
base.value = NPY_NAT
842+
base.freq = None
843843

844844
return base
845845

@@ -862,6 +862,12 @@ class NaTType(_NaT):
862862
def __long__(self):
863863
return NPY_NAT
864864

865+
def __reduce_ex__(self, protocol):
866+
# python 3.6 compat
867+
# http://bugs.python.org/issue28730
868+
# now __reduce_ex__ is defined and higher priority than __reduce__
869+
return self.__reduce__()
870+
865871
def __reduce__(self):
866872
return (__nat_unpickle, (None, ))
867873

@@ -997,6 +1003,16 @@ class NaTType(_NaT):
9971003
tz_localize = _make_nat_func('tz_localize', Timestamp)
9981004
replace = _make_nat_func('replace', Timestamp)
9991005

1006+
def to_datetime(self):
1007+
"""
1008+
DEPRECATED: use :meth:`to_pydatetime` instead.
1009+
1010+
Convert a Timestamp object to a native Python datetime object.
1011+
"""
1012+
warnings.warn("to_datetime is deprecated. Use self.to_pydatetime()",
1013+
FutureWarning, stacklevel=2)
1014+
return self.to_pydatetime(warn=False)
1015+
10001016

10011017
def __nat_unpickle(*args):
10021018
# return constant defined in the module
@@ -1143,9 +1159,9 @@ cdef class _Timestamp(datetime):
11431159
int ndim
11441160

11451161
if isinstance(other, _Timestamp):
1146-
if other is NaT:
1147-
return _cmp_nat_dt(other, self, _reverse_ops[op])
11481162
ots = other
1163+
elif other is NaT:
1164+
return _cmp_nat_dt(other, self, _reverse_ops[op])
11491165
elif PyDateTime_Check(other):
11501166
if self.nanosecond == 0:
11511167
val = self.to_pydatetime()
@@ -1448,8 +1464,7 @@ _nat_scalar_rules[Py_GE] = False
14481464

14491465

14501466
cdef _nat_divide_op(self, other):
1451-
if (PyDelta_Check(other) or
1452-
is_timedelta64_object(other) or other is NaT):
1467+
if PyDelta_Check(other) or is_timedelta64_object(other) or other is NaT:
14531468
return np.nan
14541469
if is_integer_object(other) or is_float_object(other):
14551470
return NaT
@@ -1461,7 +1476,10 @@ cdef _nat_rdivide_op(self, other):
14611476
return NotImplemented
14621477

14631478

1464-
cdef class _NaT(_Timestamp):
1479+
cdef class _NaT(datetime):
1480+
cdef readonly:
1481+
int64_t value
1482+
object freq
14651483

14661484
def __hash__(_NaT self):
14671485
# py3k needs this defined here
@@ -1475,34 +1493,52 @@ cdef class _NaT(_Timestamp):
14751493

14761494
if ndim == 0:
14771495
if is_datetime64_object(other):
1478-
other = Timestamp(other)
1496+
return _nat_scalar_rules[op]
14791497
else:
14801498
raise TypeError('Cannot compare type %r with type %r' %
14811499
(type(self).__name__, type(other).__name__))
14821500
return PyObject_RichCompare(other, self, _reverse_ops[op])
14831501

14841502
def __add__(self, other):
1485-
try:
1486-
if PyDateTime_Check(other):
1487-
return NaT
1488-
result = _Timestamp.__add__(self, other)
1489-
# Timestamp.__add__ doesn't return DatetimeIndex/TimedeltaIndex
1490-
if result is NotImplemented:
1491-
return result
1492-
except (OverflowError, OutOfBoundsDatetime):
1493-
pass
1503+
if PyDateTime_Check(other):
1504+
return NaT
1505+
1506+
elif hasattr(other, 'delta'):
1507+
# Timedelta, offsets.Tick, offsets.Week
1508+
return NaT
1509+
elif getattr(other, '_typ', None) in ['dateoffset', 'series',
1510+
'period', 'datetimeindex',
1511+
'timedeltaindex']:
1512+
# Duplicate logic in _Timestamp.__add__ to avoid needing
1513+
# to subclass; allows us to @final(_Timestamp.__add__)
1514+
return NotImplemented
14941515
return NaT
14951516

14961517
def __sub__(self, other):
1497-
if PyDateTime_Check(other) or PyDelta_Check(other):
1518+
# Duplicate some logic from _Timestamp.__sub__ to avoid needing
1519+
# to subclass; allows us to @final(_Timestamp.__sub__)
1520+
if PyDateTime_Check(other):
1521+
return NaT
1522+
elif PyDelta_Check(other):
14981523
return NaT
1499-
try:
1500-
result = _Timestamp.__sub__(self, other)
1501-
# Timestamp.__sub__ may return DatetimeIndex/TimedeltaIndex
1502-
if result is NotImplemented or hasattr(result, '_typ'):
1503-
return result
1504-
except (OverflowError, OutOfBoundsDatetime):
1505-
pass
1524+
1525+
elif getattr(other, '_typ', None) == 'datetimeindex':
1526+
# a Timestamp-DatetimeIndex -> yields a negative TimedeltaIndex
1527+
return -other.__sub__(self)
1528+
1529+
elif getattr(other, '_typ', None) == 'timedeltaindex':
1530+
# a Timestamp-TimedeltaIndex -> yields a negative TimedeltaIndex
1531+
return (-other).__add__(self)
1532+
1533+
elif hasattr(other, 'delta'):
1534+
# offsets.Tick, offsets.Week
1535+
neg_other = -other
1536+
return self + neg_other
1537+
1538+
elif getattr(other, '_typ', None) in ['period',
1539+
'periodindex', 'dateoffset']:
1540+
return NotImplemented
1541+
15061542
return NaT
15071543

15081544
def __pos__(self):
@@ -1525,6 +1561,14 @@ cdef class _NaT(_Timestamp):
15251561
return NaT
15261562
return NotImplemented
15271563

1564+
@property
1565+
def asm8(self):
1566+
return np.datetime64(NPY_NAT, 'ns')
1567+
1568+
def to_datetime64(self):
1569+
""" Returns a numpy.datetime64 object with 'ns' precision """
1570+
return np.datetime64('NaT')
1571+
15281572

15291573
# lightweight C object to hold datetime & int64 pair
15301574
cdef class _TSObject:

0 commit comments

Comments
 (0)