@@ -30,7 +30,7 @@ from util cimport (is_integer_object, is_float_object, is_datetime64_object,
3030 is_timedelta64_object, INT64_MAX)
3131cimport util
3232
33- from cpython.datetime cimport PyTZInfo_Check
33+ from cpython.datetime cimport PyDelta_Check, PyTZInfo_Check
3434# this is our datetime.pxd
3535from 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
10011017def __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
14501466cdef _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
15301574cdef class _TSObject:
0 commit comments