@@ -9,12 +9,15 @@ from cpython cimport (
9
9
PyTypeObject,
10
10
PyFloat_Check,
11
11
PyObject_RichCompareBool,
12
- PyString_Check
12
+ PyObject_RichCompare,
13
+ PyString_Check,
14
+ Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE
13
15
)
14
16
15
17
# Cython < 0.17 doesn't have this in cpython
16
18
cdef extern from " Python.h" :
17
19
cdef PyTypeObject * Py_TYPE(object )
20
+ int PySlice_Check(object )
18
21
19
22
20
23
from libc.stdlib cimport free
@@ -30,9 +33,6 @@ from datetime import timedelta, datetime
30
33
from datetime import time as datetime_time
31
34
from pandas.compat import parse_date
32
35
33
- cdef extern from " Python.h" :
34
- int PySlice_Check(object )
35
-
36
36
# initialize numpy
37
37
import_array()
38
38
# import_ufunc()
@@ -437,9 +437,35 @@ def apply_offset(ndarray[object] values, object offset):
437
437
438
438
result = np.empty(n, dtype = ' M8[ns]' )
439
439
new_values = result.view(' i8' )
440
- pass
441
440
442
441
442
+ cdef inline bint _cmp_scalar(int64_t lhs, int64_t rhs, int op) except - 1 :
443
+ if op == Py_EQ:
444
+ return lhs == rhs
445
+ elif op == Py_NE:
446
+ return lhs != rhs
447
+ elif op == Py_LT:
448
+ return lhs < rhs
449
+ elif op == Py_LE:
450
+ return lhs <= rhs
451
+ elif op == Py_GT:
452
+ return lhs > rhs
453
+ elif op == Py_GE:
454
+ return lhs >= rhs
455
+
456
+
457
+ cdef int _reverse_ops[6 ]
458
+
459
+ _reverse_ops[Py_LT] = Py_GT
460
+ _reverse_ops[Py_LE] = Py_GE
461
+ _reverse_ops[Py_EQ] = Py_EQ
462
+ _reverse_ops[Py_NE] = Py_NE
463
+ _reverse_ops[Py_GT] = Py_LT
464
+ _reverse_ops[Py_GE] = Py_LE
465
+
466
+
467
+ cdef char * _NDIM_STRING = " ndim"
468
+
443
469
# This is PITA. Because we inherit from datetime, which has very specific
444
470
# construction requirements, we need to do object instantiation in python
445
471
# (see Timestamp class above). This will serve as a C extension type that
@@ -456,12 +482,15 @@ cdef class _Timestamp(datetime):
456
482
return datetime.__hash__ (self )
457
483
458
484
def __richcmp__ (_Timestamp self , object other , int op ):
459
- cdef _Timestamp ots
460
- cdef int ndim = getattr (other, ' ndim' , - 1 )
485
+ cdef:
486
+ _Timestamp ots
487
+ int ndim = getattr (other, _NDIM_STRING, - 1 )
461
488
462
489
if isinstance (other, _Timestamp):
490
+ if isinstance (other, NaTType):
491
+ return PyObject_RichCompare(other, self , _reverse_ops[op])
463
492
ots = other
464
- elif type (other) is datetime:
493
+ elif isinstance (other, datetime) :
465
494
if self .nanosecond == 0 :
466
495
val = self .to_datetime()
467
496
return PyObject_RichCompareBool(val, other, op)
@@ -476,74 +505,40 @@ cdef class _Timestamp(datetime):
476
505
if isinstance (other, np.datetime64):
477
506
other = Timestamp(other)
478
507
else :
479
- raise TypeError (" Cannot compare Timestamp with type"
480
- " %r " % type (other).__name__)
481
- if op == 2 : # ==
482
- return other == self
483
- elif op == 3 : # !=
484
- return other != self
485
- elif op == 0 : # <
486
- return other > self
487
- elif op == 1 : # <=
488
- return other >= self
489
- elif op == 4 : # >
490
- return other < self
491
- elif op == 5 : # >=
492
- return other <= self
508
+ raise TypeError (' Cannot compare type %r with type %r ' %
509
+ (type (self ).__name__,
510
+ type (other).__name__))
511
+ return PyObject_RichCompare(other, self , _reverse_ops[op])
493
512
else :
494
- if op == 2 :
513
+ if op == Py_EQ :
495
514
return False
496
- elif op == 3 :
515
+ elif op == Py_NE :
497
516
return True
498
- else :
499
- raise TypeError (' Cannot compare Timestamp with '
500
- ' {0!r}' .format(other.__class__ .__name__ ))
517
+ raise TypeError (' Cannot compare type %r with type %r ' %
518
+ (type (self ).__name__, type (other).__name__))
501
519
502
520
self ._assert_tzawareness_compat(other)
503
-
504
- if op == 2 : # ==
505
- return self .value == ots.value
506
- elif op == 3 : # !=
507
- return self .value != ots.value
508
- elif op == 0 : # <
509
- return self .value < ots.value
510
- elif op == 1 : # <=
511
- return self .value <= ots.value
512
- elif op == 4 : # >
513
- return self .value > ots.value
514
- elif op == 5 : # >=
515
- return self .value >= ots.value
521
+ return _cmp_scalar(self .value, ots.value, op)
516
522
517
523
cdef _compare_outside_nanorange(self , object other, int op):
518
- dtval = self .to_datetime()
524
+ cdef datetime dtval = self .to_datetime()
519
525
520
526
self ._assert_tzawareness_compat(other)
521
527
522
528
if self .nanosecond == 0 :
523
- if op == 2 : # ==
524
- return dtval == other
525
- elif op == 3 : # !=
526
- return dtval != other
527
- elif op == 0 : # <
528
- return dtval < other
529
- elif op == 1 : # <=
530
- return dtval <= other
531
- elif op == 4 : # >
532
- return dtval > other
533
- elif op == 5 : # >=
534
- return dtval >= other
529
+ return PyObject_RichCompare(dtval, other, op)
535
530
else :
536
- if op == 2 : # ==
531
+ if op == Py_EQ:
537
532
return False
538
- elif op == 3 : # !=
533
+ elif op == Py_NE:
539
534
return True
540
- elif op == 0 : # <
535
+ elif op == Py_LT:
541
536
return dtval < other
542
- elif op == 1 : # <=
537
+ elif op == Py_LE:
543
538
return dtval < other
544
- elif op == 4 : # >
539
+ elif op == Py_GT:
545
540
return dtval >= other
546
- elif op == 5 : # >=
541
+ elif op == Py_GE:
547
542
return dtval >= other
548
543
549
544
cdef _assert_tzawareness_compat(self , object other):
@@ -601,49 +596,34 @@ cdef inline bint is_timestamp(object o):
601
596
return Py_TYPE(o) == ts_type # isinstance(o, Timestamp)
602
597
603
598
599
+ cdef bint _nat_scalar_rules[6 ]
600
+
601
+ _nat_scalar_rules[Py_EQ] = False
602
+ _nat_scalar_rules[Py_NE] = True
603
+ _nat_scalar_rules[Py_LT] = False
604
+ _nat_scalar_rules[Py_LE] = False
605
+ _nat_scalar_rules[Py_GT] = False
606
+ _nat_scalar_rules[Py_GE] = False
607
+
608
+
604
609
cdef class _NaT(_Timestamp):
605
610
606
611
def __hash__ (_NaT self ):
607
612
# py3k needs this defined here
608
613
return hash (self .value)
609
614
610
615
def __richcmp__ (_NaT self , object other , int op ):
611
- # if not isinstance(other, (_NaT, _Timestamp)):
612
- # raise TypeError('Cannot compare %s with NaT' % type(other))
613
616
cdef int ndim = getattr (other, ' ndim' , - 1 )
614
617
615
- if ndim != - 1 :
616
- if ndim == 0 :
617
- if isinstance (other, np.datetime64):
618
- other = Timestamp(other)
619
- else :
620
- raise TypeError (" Cannot compare NaT with type "
621
- " %r " % type (other).__name__)
622
- if op == 2 : # ==
623
- return other == self
624
- elif op == 3 : # !=
625
- return other != self
626
- elif op == 0 : # <
627
- return other > self
628
- elif op == 1 : # <=
629
- return other >= self
630
- elif op == 4 : # >
631
- return other < self
632
- elif op == 5 : # >=
633
- return other <= self
634
- else :
635
- if op == 2 : # ==
636
- return False
637
- elif op == 3 : # !=
638
- return True
639
- elif op == 0 : # <
640
- return False
641
- elif op == 1 : # <=
642
- return False
643
- elif op == 4 : # >
644
- return False
645
- elif op == 5 : # >=
646
- return False
618
+ if ndim == - 1 :
619
+ return _nat_scalar_rules[op]
620
+
621
+ if ndim == 0 :
622
+ if isinstance (other, np.datetime64):
623
+ other = Timestamp(other)
624
+ else :
625
+ raise TypeError (" asdf" )
626
+ return PyObject_RichCompare(other, self , _reverse_ops[op])
647
627
648
628
649
629
def _delta_to_nanoseconds (delta ):
0 commit comments