Skip to content

Commit 38deeaf

Browse files
committed
Refactored rounding functionality out of Timestamp
1 parent 64f8767 commit 38deeaf

File tree

1 file changed

+65
-23
lines changed

1 file changed

+65
-23
lines changed

pandas/_libs/tslibs/timestamps.pyx

Lines changed: 65 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ from timedeltas import Timedelta
3535
from timedeltas cimport delta_to_nanoseconds
3636
from 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

Comments
 (0)