1
1
from datetime import datetime, date, timedelta
2
2
import operator
3
3
4
+ from cpython cimport (
5
+ PyObject_RichCompareBool,
6
+ Py_EQ, Py_NE,
7
+ )
8
+
4
9
from numpy cimport (int8_t, int32_t, int64_t, import_array, ndarray,
5
10
NPY_INT64, NPY_DATETIME, NPY_TIMEDELTA)
6
11
import numpy as np
@@ -27,6 +32,7 @@ from tslib cimport (
27
32
_is_utc,
28
33
_is_tzlocal,
29
34
_get_dst_info,
35
+ _nat_scalar_rules,
30
36
)
31
37
32
38
from sys import version_info
@@ -615,7 +621,7 @@ def _period_field_accessor(name, alias):
615
621
return property(f)
616
622
617
623
618
- class Period (object ):
624
+ cdef class Period(object ):
619
625
"""
620
626
Represents an period of time
621
627
@@ -634,14 +640,17 @@ class Period(object):
634
640
minute : int, default 0
635
641
second : int, default 0
636
642
"""
637
- __slots__ = [' freq' , ' ordinal' ]
643
+ cdef public:
644
+ int64_t ordinal
645
+ object freq
646
+
638
647
_comparables = [' name' ,' freqstr' ]
639
648
_typ = ' period'
640
649
641
650
@classmethod
642
651
def _from_ordinal (cls , ordinal , freq ):
643
652
""" fast creation from an ordinal and freq that are already validated! """
644
- self = object .__new__ (cls )
653
+ self = Period .__new__ (cls )
645
654
self .ordinal = ordinal
646
655
self .freq = freq
647
656
return self
@@ -659,7 +668,6 @@ class Period(object):
659
668
self .freq = None
660
669
661
670
# ordinal is the period offset from the gregorian proleptic epoch
662
- self .ordinal = None
663
671
664
672
if ordinal is not None and value is not None :
665
673
raise ValueError ((" Only value or ordinal but not both should be "
@@ -669,26 +677,25 @@ class Period(object):
669
677
raise ValueError (" Ordinal must be an integer" )
670
678
if freq is None :
671
679
raise ValueError (' Must supply freq for ordinal value' )
672
- self .ordinal = ordinal
673
680
674
681
elif value is None :
675
682
if freq is None :
676
683
raise ValueError (" If value is None, freq cannot be None" )
677
684
678
- self . ordinal = _ordinal_from_fields(year, month, quarter, day,
685
+ ordinal = _ordinal_from_fields(year, month, quarter, day,
679
686
hour, minute, second, freq)
680
687
681
688
elif isinstance (value, Period):
682
689
other = value
683
690
if freq is None or _gfc(freq) == _gfc(other.freq):
684
- self . ordinal = other.ordinal
691
+ ordinal = other.ordinal
685
692
freq = other.freq
686
693
else :
687
694
converted = other.asfreq(freq)
688
- self . ordinal = converted.ordinal
695
+ ordinal = converted.ordinal
689
696
690
697
elif lib.is_null_datetimelike(value) or value in tslib._nat_strings:
691
- self . ordinal = tslib.iNaT
698
+ ordinal = tslib.iNaT
692
699
if freq is None :
693
700
raise ValueError (" If value is NaT, freq cannot be None "
694
701
" because it cannot be inferred" )
@@ -722,26 +729,30 @@ class Period(object):
722
729
# TODO: Better error message - this is slightly confusing
723
730
raise ValueError (' Only mult == 1 supported' )
724
731
725
- if self . ordinal is None :
726
- self .ordinal = period_ordinal (dt.year, dt.month, dt.day,
732
+ if ordinal is None :
733
+ self .ordinal = get_period_ordinal (dt.year, dt.month, dt.day,
727
734
dt.hour, dt.minute, dt.second, dt.microsecond, 0 ,
728
735
base)
736
+ else :
737
+ self .ordinal = ordinal
729
738
730
739
self .freq = frequencies._get_freq_str(base)
731
740
732
- def __eq__ (self , other ):
741
+ def __richcmp__ (self , other , op ):
733
742
if isinstance (other, Period):
734
743
from pandas.tseries.frequencies import get_freq_code as _gfc
735
744
if other.freq != self .freq:
736
745
raise ValueError (" Cannot compare non-conforming periods" )
737
746
if self .ordinal == tslib.iNaT or other.ordinal == tslib.iNaT:
738
- return False
739
- return (self .ordinal == other.ordinal
740
- and _gfc(self .freq) == _gfc(other.freq))
741
- return NotImplemented
742
-
743
- def __ne__ (self , other ):
744
- return not self == other
747
+ return _nat_scalar_rules[op]
748
+ return PyObject_RichCompareBool(self .ordinal, other.ordinal, op)
749
+ else :
750
+ if op == Py_EQ:
751
+ return NotImplemented
752
+ elif op == Py_NE:
753
+ return NotImplemented
754
+ raise TypeError (' Cannot compare type %r with type %r ' %
755
+ (type (self ).__name__, type (other).__name__))
745
756
746
757
def __hash__ (self ):
747
758
return hash ((self .ordinal, self .freq))
@@ -807,25 +818,6 @@ class Period(object):
807
818
else : # pragma: no cover
808
819
return NotImplemented
809
820
810
- def _comp_method (func , name ):
811
- def f (self , other ):
812
- if isinstance (other, Period):
813
- if other.freq != self .freq:
814
- raise ValueError (" Cannot compare non-conforming periods" )
815
- if self .ordinal == tslib.iNaT or other.ordinal == tslib.iNaT:
816
- return False
817
- return func(self .ordinal, other.ordinal)
818
- else :
819
- raise TypeError (other)
820
-
821
- f.__name__ = name
822
- return f
823
-
824
- __lt__ = _comp_method(operator.lt, ' __lt__' )
825
- __le__ = _comp_method(operator.le, ' __le__' )
826
- __gt__ = _comp_method(operator.gt, ' __gt__' )
827
- __ge__ = _comp_method(operator.ge, ' __ge__' )
828
-
829
821
def asfreq (self , freq , how = ' E' ):
830
822
"""
831
823
Convert Period to desired frequency, either at the start or end of the
@@ -1094,7 +1086,7 @@ def _ordinal_from_fields(year, month, quarter, day, hour, minute,
1094
1086
if quarter is not None :
1095
1087
year, month = _quarter_to_myear(year, quarter, freq)
1096
1088
1097
- return period_ordinal (year, month, day, hour, minute, second, 0 , 0 , base)
1089
+ return get_period_ordinal (year, month, day, hour, minute, second, 0 , 0 , base)
1098
1090
1099
1091
1100
1092
def _quarter_to_myear (year , quarter , freq ):
0 commit comments