@@ -22,6 +22,7 @@ cimport ccalendar
22
22
from conversion import tz_localize_to_utc, normalize_i8_timestamps
23
23
from conversion cimport (tz_convert_single, _TSObject,
24
24
convert_to_tsobject, convert_datetime_to_tsobject)
25
+ import enum
25
26
from fields import get_start_end_field, get_date_name_field
26
27
from nattype import NaT
27
28
from nattype cimport NPY_NAT
@@ -57,50 +58,42 @@ cdef inline object create_timestamp_from_ts(int64_t value,
57
58
return ts_base
58
59
59
60
60
- def round_ns (values , rounder , freq ):
61
+ class RoundTo (enum .Enum ):
62
+ MINUS_INFTY = enum .auto ()
63
+ PLUS_INFTY = enum .auto ()
64
+ NEAREST_HALF_EVEN = enum .auto ()
65
+ NEAREST_HALF_PLUS_INFTY = enum .auto ()
66
+ NEAREST_HALF_MINUS_INFTY = enum .auto ()
67
+
68
+
69
+ def round_nsint64 (values , mode , freq ):
61
70
"""
62
- Applies rounding function at given frequency
71
+ Applies rounding mode at given frequency
63
72
64
73
Parameters
65
74
----------
66
75
values : :obj:`ndarray`
67
- rounder : function, eg. 'ceil', 'floor', 'round'
76
+ mode : instance of `RoundTo` enumeration
68
77
freq : str, obj
69
78
70
79
Returns
71
80
-------
72
81
:obj:`ndarray`
73
82
"""
83
+
84
+ if not isinstance (mode, RoundTo):
85
+ raise ValueError (' mode should be a RoundTo member' )
86
+
74
87
unit = to_offset(freq).nanos
75
88
76
- # GH21262 If the Timestamp is multiple of the freq str
77
- # don't apply any rounding
78
- mask = values % unit == 0
79
- if mask.all():
80
- return values
81
- r = values.copy()
82
-
83
- if unit < 1000 :
84
- # for nano rounding, work with the last 6 digits separately
85
- # due to float precision
86
- buff = 1000000
87
- r[~ mask] = (buff * (values[~ mask] // buff) +
88
- unit * (rounder((values[~ mask] % buff) *
89
- (1 / float (unit)))).astype(' i8' ))
90
- else :
91
- if unit % 1000 != 0 :
92
- msg = ' Precision will be lost using frequency: {}'
93
- warnings.warn(msg.format(freq))
94
- # GH19206
95
- # to deal with round-off when unit is large
96
- if unit >= 1e9 :
97
- divisor = 10 ** int (np.log10(unit / 1e7 ))
98
- else :
99
- divisor = 10
100
- r[~ mask] = (unit * rounder((values[~ mask] *
101
- (divisor / float (unit))) / divisor)
102
- .astype(' i8' ))
103
- return r
89
+ if mode is RoundTo.MINUS_INFTY:
90
+ return values - (values % unit)
91
+ elif mode is RoundTo.PLUS_INFTY:
92
+ return values + (- values % unit)
93
+ elif mode is RoundTo.NEAREST_HALF_MINUS_INFTY:
94
+ return round_nsint64(values - unit// 2 , RoundTo.PLUS_INFTY, freq)
95
+
96
+ raise NotImplementedError (mode)
104
97
105
98
106
99
# This is PITA. Because we inherit from datetime, which has very specific
@@ -656,7 +649,7 @@ class Timestamp(_Timestamp):
656
649
657
650
return create_timestamp_from_ts(ts.value, ts.dts, ts.tzinfo, freq)
658
651
659
- def _round (self , freq , rounder ):
652
+ def _round (self , freq , mode ):
660
653
if self .tz is not None :
661
654
value = self .tz_localize(None ).value
662
655
else :
@@ -665,7 +658,7 @@ class Timestamp(_Timestamp):
665
658
value = np.array([value], dtype = np.int64)
666
659
667
660
# Will only ever contain 1 element for timestamp
668
- r = round_ns (value, rounder , freq)[0 ]
661
+ r = round_nsint64 (value, mode , freq)[0 ]
669
662
result = Timestamp(r, unit = ' ns' )
670
663
if self .tz is not None :
671
664
result = result.tz_localize(self .tz)
@@ -687,7 +680,7 @@ class Timestamp(_Timestamp):
687
680
------
688
681
ValueError if the freq cannot be converted
689
682
"""
690
- return self ._round(freq, np.round )
683
+ return self ._round(freq, RoundTo.NEAREST_HALF_MINUS_INFTY )
691
684
692
685
def floor (self , freq ):
693
686
"""
@@ -697,7 +690,7 @@ class Timestamp(_Timestamp):
697
690
----------
698
691
freq : a freq string indicating the flooring resolution
699
692
"""
700
- return self ._round(freq, np.floor )
693
+ return self ._round(freq, RoundTo.MINUS_INFTY )
701
694
702
695
def ceil (self , freq ):
703
696
"""
@@ -707,7 +700,7 @@ class Timestamp(_Timestamp):
707
700
----------
708
701
freq : a freq string indicating the ceiling resolution
709
702
"""
710
- return self ._round(freq, np.ceil )
703
+ return self ._round(freq, RoundTo.PLUS_INFTY )
711
704
712
705
@property
713
706
def tz (self ):
0 commit comments