From 5534c418dbe4fb54e7b1268527d38d0ccce36014 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Wed, 22 Nov 2017 20:08:17 -0800 Subject: [PATCH 1/6] small optimizations, trim namespaces --- pandas/_libs/tslibs/timedeltas.pyx | 96 ++++++------ pandas/_libs/tslibs/timestamps.pyx | 240 +++++++++++++++-------------- 2 files changed, 174 insertions(+), 162 deletions(-) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 6ea30642625fe..bfc4068adc004 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -775,6 +775,55 @@ cdef class _Timedelta(timedelta): td=components, seconds=seconds) return tpl + cdef _Timedelta _round(_Timedelta self, freq, rounder): + # Note: _round is not visible in the python namespace, so methods that + # call it must be defined in _Timedelta, not Timedelta + cdef: + int64_t result, unit + + from pandas.tseries.frequencies import to_offset + unit = to_offset(freq).nanos + result = unit * rounder(self.value / float(unit)) + return Timedelta(result, unit='ns') + + def round(self, freq): + """ + Round the Timedelta to the specified resolution + + Returns + ------- + a new Timedelta rounded to the given resolution of `freq` + + Parameters + ---------- + freq : a freq string indicating the rounding resolution + + Raises + ------ + ValueError if the freq cannot be converted + """ + return self._round(freq, np.round) + + def floor(self, freq): + """ + return a new Timedelta floored to this resolution + + Parameters + ---------- + freq : a freq string indicating the flooring resolution + """ + return self._round(freq, np.floor) + + def ceil(self, freq): + """ + return a new Timedelta ceiled to this resolution + + Parameters + ---------- + freq : a freq string indicating the ceiling resolution + """ + return self._round(freq, np.ceil) + # Python front end to C extension type _Timedelta # This serves as the box for timedelta64 @@ -865,53 +914,6 @@ class Timedelta(_Timedelta): object_state = self.value, return (Timedelta, object_state) - def _round(self, freq, rounder): - cdef: - int64_t result, unit - - from pandas.tseries.frequencies import to_offset - unit = to_offset(freq).nanos - result = unit * rounder(self.value / float(unit)) - return Timedelta(result, unit='ns') - - def round(self, freq): - """ - Round the Timedelta to the specified resolution - - Returns - ------- - a new Timedelta rounded to the given resolution of `freq` - - Parameters - ---------- - freq : a freq string indicating the rounding resolution - - Raises - ------ - ValueError if the freq cannot be converted - """ - return self._round(freq, np.round) - - def floor(self, freq): - """ - return a new Timedelta floored to this resolution - - Parameters - ---------- - freq : a freq string indicating the flooring resolution - """ - return self._round(freq, np.floor) - - def ceil(self, freq): - """ - return a new Timedelta ceiled to this resolution - - Parameters - ---------- - freq : a freq string indicating the ceiling resolution - """ - return self._round(freq, np.ceil) - # ---------------------------------------------------------------- # Arithmetic Methods # TODO: Can some of these be defined in the cython class? diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 8fdded0bcb07a..f11fbf8a88786 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -7,7 +7,7 @@ from cpython cimport (PyObject_RichCompareBool, PyObject_RichCompare, import numpy as np cimport numpy as np -from numpy cimport int64_t, int32_t, ndarray +from numpy cimport int64_t, int32_t, int8_t, ndarray np.import_array() from datetime import time as datetime_time @@ -172,8 +172,8 @@ cdef class _Timestamp(datetime): elif op == Py_GE: return dtval >= other - cdef int _assert_tzawareness_compat(_Timestamp self, - object other) except -1: + cdef void _assert_tzawareness_compat(_Timestamp self, + object other) except -1: if self.tzinfo is None: if other.tzinfo is not None: raise TypeError('Cannot compare tz-naive and tz-aware ' @@ -209,6 +209,7 @@ cdef class _Timestamp(datetime): """ Returns a numpy.datetime64 object with 'ns' precision """ return np.datetime64(self.value, 'ns') + @cython.final def __add__(self, other): cdef int64_t other_int, nanos @@ -246,6 +247,7 @@ cdef class _Timestamp(datetime): result.nanosecond = self.nanosecond return result + @cython.final def __sub__(self, other): if (is_timedelta64_object(other) or is_integer_object(other) or PyDelta_Check(other) or hasattr(other, 'delta')): @@ -296,7 +298,10 @@ cdef class _Timestamp(datetime): val = tz_convert_single(self.value, 'UTC', self.tz) return val - cpdef int _get_field(self, field): + cdef int _get_field(_Timestamp self, field): + # Note: because _get_field is `cdef`, it is not visible in the python + # namespace. Any methods that need to call `_get_field` must be + # defined in _Timestamp, not Timestamp. cdef: int64_t val ndarray[int32_t] out @@ -304,10 +309,30 @@ cdef class _Timestamp(datetime): out = get_date_field(np.array([val], dtype=np.int64), field) return int(out[0]) - cpdef _get_start_end_field(self, field): + @property + def dayofyear(self): + return self._get_field('doy') + + @property + def week(self): + return self._get_field('woy') + + @property + def quarter(self): + return self._get_field('q') + + @property + def days_in_month(self): + return self._get_field('dim') + + cdef int8_t _get_start_end_field(_Timestamp self, field): + # Note: because _get_start_end_field is `cdef`, it is not visible + # in the python namespace. Any methods that need to call + # `_get_start_end_field` must be defined in _Timestamp, not Timestamp. cdef: int64_t val dict kwds + ndarray[int8_t] out freq = self.freq if freq: @@ -323,6 +348,30 @@ cdef class _Timestamp(datetime): field, freqstr, month_kw) return out[0] + @property + def is_month_start(self): + return self._get_start_end_field('is_month_start') + + @property + def is_month_end(self): + return self._get_start_end_field('is_month_end') + + @property + def is_quarter_start(self): + return self._get_start_end_field('is_quarter_start') + + @property + def is_quarter_end(self): + return self._get_start_end_field('is_quarter_end') + + @property + def is_year_start(self): + return self._get_start_end_field('is_year_start') + + @property + def is_year_end(self): + return self._get_start_end_field('is_year_end') + @property def _repr_base(self): return '{date} {time}'.format(date=self._date_repr, @@ -366,6 +415,73 @@ cdef class _Timestamp(datetime): # py27 compat, see GH#17329 return round(self.value / 1e9, 6) + cdef _Timestamp _round(_Timestamp self, freq, rounder): + # Note: _round is not visible in the python namespace, so methods that + # call it must be defined in _Timestamp, not Timestamp + cdef: + int64_t unit, rounded, value, buff = 1000000 + _Timestamp result + + from pandas.tseries.frequencies import to_offset + unit = to_offset(freq).nanos + if self.tz is not None: + value = self.tz_localize(None).value + else: + value = self.value + if unit < 1000 and unit % 1000 != 0: + # for nano rounding, work with the last 6 digits separately + # due to float precision + rounded = (buff * (value // buff) + unit * + (rounder((value % buff) / float(unit))).astype('i8')) + elif unit >= 1000 and unit % 1000 != 0: + msg = 'Precision will be lost using frequency: {}' + warnings.warn(msg.format(freq)) + rounded = (unit * rounder(value / float(unit)).astype('i8')) + else: + rounded = (unit * rounder(value / float(unit)).astype('i8')) + result = Timestamp(rounded, unit='ns') + if self.tz is not None: + result = result.tz_localize(self.tz) + return result + + def round(self, freq): + """ + Round the Timestamp to the specified resolution + + Returns + ------- + a new Timestamp rounded to the given resolution of `freq` + + Parameters + ---------- + freq : a freq string indicating the rounding resolution + + Raises + ------ + ValueError if the freq cannot be converted + """ + return self._round(freq, np.round) + + def floor(self, freq): + """ + return a new Timestamp floored to this resolution + + Parameters + ---------- + freq : a freq string indicating the flooring resolution + """ + return self._round(freq, np.floor) + + def ceil(self, freq): + """ + return a new Timestamp ceiled to this resolution + + Parameters + ---------- + freq : a freq string indicating the ceiling resolution + """ + return self._round(freq, np.ceil) + # ---------------------------------------------------------------------- @@ -591,72 +707,6 @@ class Timestamp(_Timestamp): return create_timestamp_from_ts(ts.value, ts.dts, ts.tzinfo, freq) - def _round(self, freq, rounder): - - cdef: - int64_t unit, r, value, buff = 1000000 - object result - - from pandas.tseries.frequencies import to_offset - unit = to_offset(freq).nanos - if self.tz is not None: - value = self.tz_localize(None).value - else: - value = self.value - if unit < 1000 and unit % 1000 != 0: - # for nano rounding, work with the last 6 digits separately - # due to float precision - r = (buff * (value // buff) + unit * - (rounder((value % buff) / float(unit))).astype('i8')) - elif unit >= 1000 and unit % 1000 != 0: - msg = 'Precision will be lost using frequency: {}' - warnings.warn(msg.format(freq)) - r = (unit * rounder(value / float(unit)).astype('i8')) - else: - r = (unit * rounder(value / float(unit)).astype('i8')) - result = Timestamp(r, unit='ns') - if self.tz is not None: - result = result.tz_localize(self.tz) - return result - - def round(self, freq): - """ - Round the Timestamp to the specified resolution - - Returns - ------- - a new Timestamp rounded to the given resolution of `freq` - - Parameters - ---------- - freq : a freq string indicating the rounding resolution - - Raises - ------ - ValueError if the freq cannot be converted - """ - return self._round(freq, np.round) - - def floor(self, freq): - """ - return a new Timestamp floored to this resolution - - Parameters - ---------- - freq : a freq string indicating the flooring resolution - """ - return self._round(freq, np.floor) - - def ceil(self, freq): - """ - return a new Timestamp ceiled to this resolution - - Parameters - ---------- - freq : a freq string indicating the ceiling resolution - """ - return self._round(freq, np.ceil) - @property def tz(self): """ @@ -701,54 +751,10 @@ class Timestamp(_Timestamp): 6: 'Sunday'} return wdays[self.weekday()] - @property - def dayofyear(self): - return self._get_field('doy') - - @property - def week(self): - return self._get_field('woy') - - weekofyear = week - - @property - def quarter(self): - return self._get_field('q') - - @property - def days_in_month(self): - return self._get_field('dim') - - daysinmonth = days_in_month - @property def freqstr(self): return getattr(self.freq, 'freqstr', self.freq) - @property - def is_month_start(self): - return self._get_start_end_field('is_month_start') - - @property - def is_month_end(self): - return self._get_start_end_field('is_month_end') - - @property - def is_quarter_start(self): - return self._get_start_end_field('is_quarter_start') - - @property - def is_quarter_end(self): - return self._get_start_end_field('is_quarter_end') - - @property - def is_year_start(self): - return self._get_start_end_field('is_year_start') - - @property - def is_year_end(self): - return self._get_start_end_field('is_year_end') - @property def is_leap_year(self): return bool(is_leapyear(self.year)) @@ -982,6 +988,10 @@ class Timestamp(_Timestamp): return self + other +# property aliases +Timestamp.daysinmonth = Timestamp.days_in_month +Timestamp.weekofyear = Timestamp.week + # Add the min and max fields at the class level cdef int64_t _NS_UPPER_BOUND = INT64_MAX # the smallest value we could actually represent is From 59b58a00ce141907c8fe3dbab480391ff34980cb Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Wed, 22 Nov 2017 21:27:18 -0800 Subject: [PATCH 2/6] fixup missing cimport --- pandas/_libs/tslibs/timestamps.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index f11fbf8a88786..753dbc07d1941 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -5,6 +5,8 @@ import warnings from cpython cimport (PyObject_RichCompareBool, PyObject_RichCompare, Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE) +cimport cython + import numpy as np cimport numpy as np from numpy cimport int64_t, int32_t, int8_t, ndarray From 9166ab6b94babaad09701cff81e728b242652c98 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Thu, 23 Nov 2017 07:32:01 -0800 Subject: [PATCH 3/6] revert change that broke build --- pandas/_libs/tslibs/timestamps.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 753dbc07d1941..277a77fb835d8 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -174,8 +174,8 @@ cdef class _Timestamp(datetime): elif op == Py_GE: return dtval >= other - cdef void _assert_tzawareness_compat(_Timestamp self, - object other) except -1: + cdef int _assert_tzawareness_compat(_Timestamp self, + object other) except -1: if self.tzinfo is None: if other.tzinfo is not None: raise TypeError('Cannot compare tz-naive and tz-aware ' From 37501e42f76db3ed58bd07cd127b328315f05348 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Fri, 24 Nov 2017 08:40:47 -0800 Subject: [PATCH 4/6] remove cython.final, add default freq to round for cython compat --- pandas/_libs/tslibs/timestamps.pyx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 277a77fb835d8..c69a662bd94ea 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -211,7 +211,6 @@ cdef class _Timestamp(datetime): """ Returns a numpy.datetime64 object with 'ns' precision """ return np.datetime64(self.value, 'ns') - @cython.final def __add__(self, other): cdef int64_t other_int, nanos @@ -249,7 +248,6 @@ cdef class _Timestamp(datetime): result.nanosecond = self.nanosecond return result - @cython.final def __sub__(self, other): if (is_timedelta64_object(other) or is_integer_object(other) or PyDelta_Check(other) or hasattr(other, 'delta')): @@ -327,14 +325,16 @@ cdef class _Timestamp(datetime): def days_in_month(self): return self._get_field('dim') - cdef int8_t _get_start_end_field(_Timestamp self, field): + cdef bint _get_start_end_field(_Timestamp self, field): # Note: because _get_start_end_field is `cdef`, it is not visible # in the python namespace. Any methods that need to call # `_get_start_end_field` must be defined in _Timestamp, not Timestamp. cdef: int64_t val dict kwds - ndarray[int8_t] out + # Note: As of 2017-11-23, adding a type declaration for `out` + # results in a ValueError when any of these properties are accessed + # "Does not understand character buffer dtype format string ('?')" freq = self.freq if freq: @@ -348,7 +348,7 @@ cdef class _Timestamp(datetime): val = self._maybe_convert_value_to_local() out = get_start_end_field(np.array([val], dtype=np.int64), field, freqstr, month_kw) - return out[0] + return bool(out[0]) @property def is_month_start(self): @@ -446,7 +446,7 @@ cdef class _Timestamp(datetime): result = result.tz_localize(self.tz) return result - def round(self, freq): + def round(self, freq='D'): """ Round the Timestamp to the specified resolution @@ -464,7 +464,7 @@ cdef class _Timestamp(datetime): """ return self._round(freq, np.round) - def floor(self, freq): + def floor(self, freq='D'): """ return a new Timestamp floored to this resolution @@ -474,7 +474,7 @@ cdef class _Timestamp(datetime): """ return self._round(freq, np.floor) - def ceil(self, freq): + def ceil(self, freq='D'): """ return a new Timestamp ceiled to this resolution From 028ac996f99084005ecbfbf06a37e7f96fe68591 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Fri, 24 Nov 2017 11:34:01 -0800 Subject: [PATCH 5/6] revert changes to rounding methods --- pandas/_libs/tslibs/timedeltas.pyx | 96 ++++++++++---------- pandas/_libs/tslibs/timestamps.pyx | 135 ++++++++++++++--------------- 2 files changed, 113 insertions(+), 118 deletions(-) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index bfc4068adc004..6ea30642625fe 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -775,55 +775,6 @@ cdef class _Timedelta(timedelta): td=components, seconds=seconds) return tpl - cdef _Timedelta _round(_Timedelta self, freq, rounder): - # Note: _round is not visible in the python namespace, so methods that - # call it must be defined in _Timedelta, not Timedelta - cdef: - int64_t result, unit - - from pandas.tseries.frequencies import to_offset - unit = to_offset(freq).nanos - result = unit * rounder(self.value / float(unit)) - return Timedelta(result, unit='ns') - - def round(self, freq): - """ - Round the Timedelta to the specified resolution - - Returns - ------- - a new Timedelta rounded to the given resolution of `freq` - - Parameters - ---------- - freq : a freq string indicating the rounding resolution - - Raises - ------ - ValueError if the freq cannot be converted - """ - return self._round(freq, np.round) - - def floor(self, freq): - """ - return a new Timedelta floored to this resolution - - Parameters - ---------- - freq : a freq string indicating the flooring resolution - """ - return self._round(freq, np.floor) - - def ceil(self, freq): - """ - return a new Timedelta ceiled to this resolution - - Parameters - ---------- - freq : a freq string indicating the ceiling resolution - """ - return self._round(freq, np.ceil) - # Python front end to C extension type _Timedelta # This serves as the box for timedelta64 @@ -914,6 +865,53 @@ class Timedelta(_Timedelta): object_state = self.value, return (Timedelta, object_state) + def _round(self, freq, rounder): + cdef: + int64_t result, unit + + from pandas.tseries.frequencies import to_offset + unit = to_offset(freq).nanos + result = unit * rounder(self.value / float(unit)) + return Timedelta(result, unit='ns') + + def round(self, freq): + """ + Round the Timedelta to the specified resolution + + Returns + ------- + a new Timedelta rounded to the given resolution of `freq` + + Parameters + ---------- + freq : a freq string indicating the rounding resolution + + Raises + ------ + ValueError if the freq cannot be converted + """ + return self._round(freq, np.round) + + def floor(self, freq): + """ + return a new Timedelta floored to this resolution + + Parameters + ---------- + freq : a freq string indicating the flooring resolution + """ + return self._round(freq, np.floor) + + def ceil(self, freq): + """ + return a new Timedelta ceiled to this resolution + + Parameters + ---------- + freq : a freq string indicating the ceiling resolution + """ + return self._round(freq, np.ceil) + # ---------------------------------------------------------------- # Arithmetic Methods # TODO: Can some of these be defined in the cython class? diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index c69a662bd94ea..f15aae89ae8c2 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -5,8 +5,6 @@ import warnings from cpython cimport (PyObject_RichCompareBool, PyObject_RichCompare, Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE) -cimport cython - import numpy as np cimport numpy as np from numpy cimport int64_t, int32_t, int8_t, ndarray @@ -417,73 +415,6 @@ cdef class _Timestamp(datetime): # py27 compat, see GH#17329 return round(self.value / 1e9, 6) - cdef _Timestamp _round(_Timestamp self, freq, rounder): - # Note: _round is not visible in the python namespace, so methods that - # call it must be defined in _Timestamp, not Timestamp - cdef: - int64_t unit, rounded, value, buff = 1000000 - _Timestamp result - - from pandas.tseries.frequencies import to_offset - unit = to_offset(freq).nanos - if self.tz is not None: - value = self.tz_localize(None).value - else: - value = self.value - if unit < 1000 and unit % 1000 != 0: - # for nano rounding, work with the last 6 digits separately - # due to float precision - rounded = (buff * (value // buff) + unit * - (rounder((value % buff) / float(unit))).astype('i8')) - elif unit >= 1000 and unit % 1000 != 0: - msg = 'Precision will be lost using frequency: {}' - warnings.warn(msg.format(freq)) - rounded = (unit * rounder(value / float(unit)).astype('i8')) - else: - rounded = (unit * rounder(value / float(unit)).astype('i8')) - result = Timestamp(rounded, unit='ns') - if self.tz is not None: - result = result.tz_localize(self.tz) - return result - - def round(self, freq='D'): - """ - Round the Timestamp to the specified resolution - - Returns - ------- - a new Timestamp rounded to the given resolution of `freq` - - Parameters - ---------- - freq : a freq string indicating the rounding resolution - - Raises - ------ - ValueError if the freq cannot be converted - """ - return self._round(freq, np.round) - - def floor(self, freq='D'): - """ - return a new Timestamp floored to this resolution - - Parameters - ---------- - freq : a freq string indicating the flooring resolution - """ - return self._round(freq, np.floor) - - def ceil(self, freq='D'): - """ - return a new Timestamp ceiled to this resolution - - Parameters - ---------- - freq : a freq string indicating the ceiling resolution - """ - return self._round(freq, np.ceil) - # ---------------------------------------------------------------------- @@ -709,6 +640,72 @@ class Timestamp(_Timestamp): return create_timestamp_from_ts(ts.value, ts.dts, ts.tzinfo, freq) + def _round(self, freq, rounder): + + cdef: + int64_t unit, rounded, value, buff = 1000000 + object result + + from pandas.tseries.frequencies import to_offset + unit = to_offset(freq).nanos + if self.tz is not None: + value = self.tz_localize(None).value + else: + value = self.value + if unit < 1000 and unit % 1000 != 0: + # for nano rounding, work with the last 6 digits separately + # due to float precision + rounded = (buff * (value // buff) + unit * + (rounder((value % buff) / float(unit))).astype('i8')) + elif unit >= 1000 and unit % 1000 != 0: + msg = 'Precision will be lost using frequency: {}' + warnings.warn(msg.format(freq)) + rounded = (unit * rounder(value / float(unit)).astype('i8')) + else: + rounded = (unit * rounder(value / float(unit)).astype('i8')) + result = Timestamp(rounded, unit='ns') + if self.tz is not None: + result = result.tz_localize(self.tz) + return result + + def round(self, freq): + """ + Round the Timestamp to the specified resolution + + Returns + ------- + a new Timestamp rounded to the given resolution of `freq` + + Parameters + ---------- + freq : a freq string indicating the rounding resolution + + Raises + ------ + ValueError if the freq cannot be converted + """ + return self._round(freq, np.round) + + def floor(self, freq): + """ + return a new Timestamp floored to this resolution + + Parameters + ---------- + freq : a freq string indicating the flooring resolution + """ + return self._round(freq, np.floor) + + def ceil(self, freq): + """ + return a new Timestamp ceiled to this resolution + + Parameters + ---------- + freq : a freq string indicating the ceiling resolution + """ + return self._round(freq, np.ceil) + @property def tz(self): """ From e4d5f7f419408183c246e6385b8864b4458ac019 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Fri, 24 Nov 2017 11:35:23 -0800 Subject: [PATCH 6/6] revert change to variable name r-->roudned --- pandas/_libs/tslibs/timestamps.pyx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index f15aae89ae8c2..8ae13afd5afb6 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -643,7 +643,7 @@ class Timestamp(_Timestamp): def _round(self, freq, rounder): cdef: - int64_t unit, rounded, value, buff = 1000000 + int64_t unit, r, value, buff = 1000000 object result from pandas.tseries.frequencies import to_offset @@ -655,15 +655,15 @@ class Timestamp(_Timestamp): if unit < 1000 and unit % 1000 != 0: # for nano rounding, work with the last 6 digits separately # due to float precision - rounded = (buff * (value // buff) + unit * - (rounder((value % buff) / float(unit))).astype('i8')) + r = (buff * (value // buff) + unit * + (rounder((value % buff) / float(unit))).astype('i8')) elif unit >= 1000 and unit % 1000 != 0: msg = 'Precision will be lost using frequency: {}' warnings.warn(msg.format(freq)) - rounded = (unit * rounder(value / float(unit)).astype('i8')) + r = (unit * rounder(value / float(unit)).astype('i8')) else: - rounded = (unit * rounder(value / float(unit)).astype('i8')) - result = Timestamp(rounded, unit='ns') + r = (unit * rounder(value / float(unit)).astype('i8')) + result = Timestamp(r, unit='ns') if self.tz is not None: result = result.tz_localize(self.tz) return result