diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index 61cf582300034..c1a0e58a4fb1a 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -35,18 +35,17 @@ from cython cimport Py_ssize_t import pytz -UTC = pytz.utc from tslibs.timedeltas cimport cast_from_unit -from tslibs.timedeltas import Timedelta +from tslibs.timedeltas import Timedelta, ints_to_pytimedelta # noqa:F841 from tslibs.timezones cimport (is_utc, is_tzlocal, is_fixed_offset, treat_tz_as_pytz, get_dst_info) from tslibs.conversion cimport (tz_convert_single, _TSObject, convert_datetime_to_tsobject, get_datetime64_nanos, tz_convert_utc_to_tzlocal) -from tslibs.conversion import tz_convert_single +from tslibs.conversion import tz_convert_single, normalize_date # noqa:F841 from tslibs.nattype import NaT, nat_strings, iNaT from tslibs.nattype cimport checknull_with_nat, NPY_NAT @@ -185,29 +184,6 @@ def ints_to_pydatetime(ndarray[int64_t] arr, tz=None, freq=None, return result -def ints_to_pytimedelta(ndarray[int64_t] arr, box=False): - # convert an i8 repr to an ndarray of timedelta or Timedelta (if box == - # True) - - cdef: - Py_ssize_t i, n = len(arr) - int64_t value - ndarray[object] result = np.empty(n, dtype=object) - - for i in range(n): - - value = arr[i] - if value == NPY_NAT: - result[i] = NaT - else: - if box: - result[i] = Timedelta(value) - else: - result[i] = timedelta(microseconds=int(value) / 1000) - - return result - - def _test_parse_iso8601(object ts): """ TESTING ONLY: Parse string into Timestamp using iso8601 parser. Used @@ -740,30 +716,3 @@ cdef inline bint _parse_today_now(str val, int64_t* iresult): iresult[0] = Timestamp.today().value return True return False - -# ---------------------------------------------------------------------- -# Some general helper functions - - -cpdef normalize_date(object dt): - """ - Normalize datetime.datetime value to midnight. Returns datetime.date as a - datetime.datetime at midnight - - Returns - ------- - normalized : datetime.datetime or Timestamp - """ - if PyDateTime_Check(dt): - if not PyDateTime_CheckExact(dt): - # i.e. a Timestamp object - return dt.replace(hour=0, minute=0, second=0, microsecond=0, - nanosecond=0) - else: - # regular datetime object - return dt.replace(hour=0, minute=0, second=0, microsecond=0) - # TODO: Make sure DST crossing is handled correctly here - elif PyDate_Check(dt): - return datetime(dt.year, dt.month, dt.day) - else: - raise TypeError('Unrecognized type: %s' % type(dt)) diff --git a/pandas/_libs/tslibs/__init__.py b/pandas/_libs/tslibs/__init__.py index f3aa0424f0376..22307f70ebe52 100644 --- a/pandas/_libs/tslibs/__init__.py +++ b/pandas/_libs/tslibs/__init__.py @@ -1,2 +1,8 @@ # -*- coding: utf-8 -*- -# cython: profile=False +# flake8: noqa + +from .conversion import normalize_date, localize_pydatetime, tz_convert_single +from .nattype import NaT, iNaT +from .np_datetime import OutOfBoundsDatetime +from .timestamps import Timestamp +from .timedeltas import delta_to_nanoseconds, ints_to_pytimedelta, Timedelta diff --git a/pandas/_libs/tslibs/conversion.pyx b/pandas/_libs/tslibs/conversion.pyx index f825a4c8ed2c1..fd4b0b11065ed 100644 --- a/pandas/_libs/tslibs/conversion.pyx +++ b/pandas/_libs/tslibs/conversion.pyx @@ -1025,6 +1025,35 @@ cdef inline str _render_tstamp(int64_t val): # ---------------------------------------------------------------------- # Normalization + +def normalize_date(object dt): + """ + Normalize datetime.datetime value to midnight. Returns datetime.date as a + datetime.datetime at midnight + + Parameters + ---------- + dt : date, datetime, or Timestamp + + Returns + ------- + normalized : datetime.datetime or Timestamp + """ + if PyDateTime_Check(dt): + if not PyDateTime_CheckExact(dt): + # i.e. a Timestamp object + return dt.replace(hour=0, minute=0, second=0, microsecond=0, + nanosecond=0) + else: + # regular datetime object + return dt.replace(hour=0, minute=0, second=0, microsecond=0) + # TODO: Make sure DST crossing is handled correctly here + elif PyDate_Check(dt): + return datetime(dt.year, dt.month, dt.day) + else: + raise TypeError('Unrecognized type: %s' % type(dt)) + + @cython.wraparound(False) @cython.boundscheck(False) def date_normalize(ndarray[int64_t] stamps, tz=None): diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 27066af0be3b9..76849f2116123 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -79,6 +79,44 @@ cdef dict timedelta_abbrevs = { 'D': 'd', _no_input = object() + +# ---------------------------------------------------------------------- +# API + +def ints_to_pytimedelta(ndarray[int64_t] arr, box=False): + """ + convert an i8 repr to an ndarray of timedelta or Timedelta (if box == + True) + + Parameters + ---------- + arr : ndarray[int64_t] + box : bool, default False + + Returns + ------- + result : ndarray[object] + array of Timedelta or timedeltas objects + """ + cdef: + Py_ssize_t i, n = len(arr) + int64_t value + ndarray[object] result = np.empty(n, dtype=object) + + for i in range(n): + + value = arr[i] + if value == NPY_NAT: + result[i] = NaT + else: + if box: + result[i] = Timedelta(value) + else: + result[i] = timedelta(microseconds=int(value) / 1000) + + return result + + # ---------------------------------------------------------------------- cpdef int64_t delta_to_nanoseconds(delta) except? -1: diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 54d29cea44555..401ba76e341b2 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -645,7 +645,6 @@ class Timestamp(_Timestamp): return NaT if is_string_object(freq): - from pandas.tseries.frequencies import to_offset freq = to_offset(freq) return create_timestamp_from_ts(ts.value, ts.dts, ts.tzinfo, freq) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 26c23b84a9c04..818dd1b408518 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -7156,7 +7156,6 @@ def first(self, offset): at_time : Select values at a particular time of the day between_time : Select values between particular times of the day """ - from pandas.tseries.frequencies import to_offset if not isinstance(self.index, DatetimeIndex): raise TypeError("'first' only supports a DatetimeIndex index") @@ -7220,7 +7219,6 @@ def last(self, offset): at_time : Select values at a particular time of the day between_time : Select values between particular times of the day """ - from pandas.tseries.frequencies import to_offset if not isinstance(self.index, DatetimeIndex): raise TypeError("'last' only supports a DatetimeIndex index") diff --git a/pandas/tests/tseries/offsets/test_offsets.py b/pandas/tests/tseries/offsets/test_offsets.py index 0c5470e7bd932..a5cd839c1472f 100644 --- a/pandas/tests/tseries/offsets/test_offsets.py +++ b/pandas/tests/tseries/offsets/test_offsets.py @@ -33,7 +33,7 @@ import pandas.tseries.offsets as offsets from pandas.io.pickle import read_pickle from pandas._libs.tslibs import timezones -from pandas._libs.tslib import normalize_date, NaT, Timestamp +from pandas._libs.tslib import NaT, Timestamp import pandas._libs.tslib as tslib import pandas.util.testing as tm from pandas.tseries.holiday import USFederalHolidayCalendar @@ -59,11 +59,6 @@ def test_ole2datetime(): ole2datetime(60) -def test_normalize_date(): - actual = normalize_date(datetime(2007, 10, 1, 1, 12, 5, 10)) - assert actual == datetime(2007, 10, 1) - - def test_to_m8(): valb = datetime(2007, 10, 1) valu = _to_m8(valb) diff --git a/pandas/tests/tslibs/test_tslib.py b/pandas/tests/tslibs/test_tslib.py index 2641c016e8674..484ec71cdc4c1 100644 --- a/pandas/tests/tslibs/test_tslib.py +++ b/pandas/tests/tslibs/test_tslib.py @@ -16,3 +16,8 @@ def test_normalize_date(): result = tslib.normalize_date(value) assert (result == datetime(2012, 9, 7)) + + value = datetime(2007, 10, 1, 1, 12, 5, 10) + + actual = tslib.normalize_date(value) + assert actual == datetime(2007, 10, 1)