@@ -35,6 +35,7 @@ from timedeltas import Timedelta
3535from timedeltas cimport delta_to_nanoseconds
3636from timezones cimport (
3737 get_timezone, is_utc, maybe_get_tz, treat_tz_as_pytz, tz_compare)
38+ from pandas.tseries.frequencies import to_offset
3839
3940# ----------------------------------------------------------------------
4041# Constants
@@ -59,6 +60,45 @@ cdef inline object create_timestamp_from_ts(int64_t value,
5960 return ts_base
6061
6162
63+ def round_ns (values , rounder , freq ):
64+ """
65+ Applies rounding function at given frequency
66+
67+ Parameters
68+ ----------
69+ values : int, :obj:`ndarray`
70+ rounder : function
71+ freq : str, obj
72+
73+ Returns
74+ -------
75+ int or :obj:`ndarray`
76+ """
77+ unit = to_offset(freq).nanos
78+ if unit < 1000 :
79+ # for nano rounding, work with the last 6 digits separately
80+ # due to float precision
81+ buff = 1000000
82+ r = (buff * (values // buff) + unit *
83+ (rounder((values % buff) * (1 / float (unit)))).astype(' i8' ))
84+ else :
85+ if unit % 1000 != 0 :
86+ msg = ' Precision will be lost using frequency: {}'
87+ warnings.warn(msg.format(freq))
88+
89+ # GH19206
90+ # to deal with round-off when unit is large
91+ if unit >= 1e9 :
92+ divisor = 10 ** int (np.log10(unit / 1e7 ))
93+ else :
94+ divisor = 10
95+
96+ r = (unit * rounder((values * (divisor / float (unit))) / divisor)
97+ .astype(' i8' ))
98+
99+ return r
100+
101+
62102# This is PITA. Because we inherit from datetime, which has very specific
63103# construction requirements, we need to do object instantiation in python
64104# (see Timestamp class above). This will serve as a C extension type that
@@ -591,36 +631,38 @@ class Timestamp(_Timestamp):
591631
592632 def _round (self , freq , rounder ):
593633
594- cdef:
595- int64_t unit, r, value, buff = 1000000
596- object result
634+ # cdef:
635+ # int64_t unit, r, value, buff = 1000000
636+ # object result
597637
598- from pandas.tseries.frequencies import to_offset
599- unit = to_offset(freq).nanos
638+ # from pandas.tseries.frequencies import to_offset
639+ # unit = to_offset(freq).nanos
600640 if self .tz is not None :
601641 value = self .tz_localize(None ).value
602642 else :
603643 value = self .value
604- if unit < 1000 :
605- # for nano rounding, work with the last 6 digits separately
606- # due to float precision
607- r = (buff * (value // buff) + unit *
608- (rounder((value % buff) * (1 / float (unit)))).astype(' i8' ))
609- else :
610- if unit % 1000 != 0 :
611- msg = ' Precision will be lost using frequency: {}'
612- warnings.warn(msg.format(freq))
613-
614- # GH19206
615- # to deal with round-off when unit is large
616- if unit >= 1e9 :
617- divisor = 10 ** int (np.log10(unit / 1e7 ))
618- else :
619- divisor = 10
620644
621- r = (unit * rounder((value * (divisor / float (unit))) / divisor)
622- .astype(' i8' ))
645+ # if unit < 1000:
646+ # # for nano rounding, work with the last 6 digits separately
647+ # # due to float precision
648+ # r = (buff * (value // buff) + unit *
649+ # (rounder((value % buff) * (1 / float(unit)))).astype('i8'))
650+ # else:
651+ # if unit % 1000 != 0:
652+ # msg = 'Precision will be lost using frequency: {}'
653+ # warnings.warn(msg.format(freq))
654+ #
655+ # # GH19206
656+ # # to deal with round-off when unit is large
657+ # if unit >= 1e9:
658+ # divisor = 10 ** int(np.log10(unit / 1e7))
659+ # else:
660+ # divisor = 10
661+ #
662+ # r = (unit * rounder((value * (divisor / float(unit))) / divisor)
663+ # .astype('i8'))
623664
665+ r = round_ns(value, rounder, freq)
624666 result = Timestamp(r, unit = ' ns' )
625667 if self .tz is not None :
626668 result = result.tz_localize(self .tz)
0 commit comments