diff --git a/pandas/_libs/index.pyx b/pandas/_libs/index.pyx index 884117799ec5b..9e55f2c3631b5 100644 --- a/pandas/_libs/index.pyx +++ b/pandas/_libs/index.pyx @@ -13,28 +13,19 @@ cimport util import numpy as np -cimport tslib - from hashtable cimport HashTable from tslibs.timezones cimport is_utc, get_utcoffset +from tslibs.conversion cimport _to_i8 from pandas._libs import tslib, algos, hashtable as _hash from pandas._libs.tslib import Timestamp, Timedelta from datetime import datetime, timedelta -from datetime cimport (get_datetime64_value, _pydatetime_to_dts, - pandas_datetimestruct) - from cpython cimport PyTuple_Check, PyList_Check -cdef extern from "datetime.h": - bint PyDateTime_Check(object o) - void PyDateTime_IMPORT() - cdef int64_t iNaT = util.get_nat() -PyDateTime_IMPORT cdef extern from "Python.h": int PySlice_Check(object) @@ -540,23 +531,6 @@ cpdef convert_scalar(ndarray arr, object value): return value -cdef inline _to_i8(object val): - cdef pandas_datetimestruct dts - try: - return val.value - except AttributeError: - if util.is_datetime64_object(val): - return get_datetime64_value(val) - elif PyDateTime_Check(val): - tzinfo = getattr(val, 'tzinfo', None) - # Save the original date value so we can get the utcoffset from it. - ival = _pydatetime_to_dts(val, &dts) - if tzinfo is not None and not is_utc(tzinfo): - offset = get_utcoffset(tzinfo, val) - ival -= tslib._delta_to_nanoseconds(offset) - return ival - return val - cdef class MultiIndexObjectEngine(ObjectEngine): """ diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index 01548e17d39ab..47acc63cc5742 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -45,8 +45,6 @@ cdef double NaN = np.NaN cdef double nan = NaN cdef double NAN = nan -from datetime import datetime as pydatetime - # this is our tseries.pxd from datetime cimport ( get_timedelta64_value, get_datetime64_value, @@ -134,58 +132,10 @@ def memory_usage_of_objects(ndarray[object, ndim=1] arr): #---------------------------------------------------------------------- # datetime / io related - -cdef int _EPOCH_ORD = 719163 - -from datetime import date as pydate - -cdef inline int64_t gmtime(object date): - cdef int y, m, d, h, mn, s, days - - y = PyDateTime_GET_YEAR(date) - m = PyDateTime_GET_MONTH(date) - d = PyDateTime_GET_DAY(date) - h = PyDateTime_DATE_GET_HOUR(date) - mn = PyDateTime_DATE_GET_MINUTE(date) - s = PyDateTime_DATE_GET_SECOND(date) - - days = pydate(y, m, 1).toordinal() - _EPOCH_ORD + d - 1 - return (( (((days * 24 + h) * 60 + mn))) * 60 + s) * 1000 - - -cpdef object to_datetime(int64_t timestamp): - return pydatetime.utcfromtimestamp(timestamp / 1000.0) - - -cpdef object to_timestamp(object dt): - return gmtime(dt) - - -def array_to_timestamp(ndarray[object, ndim=1] arr): - cdef int i, n - cdef ndarray[int64_t, ndim=1] result - - n = len(arr) - result = np.empty(n, dtype=np.int64) - - for i from 0 <= i < n: - result[i] = gmtime(arr[i]) - - return result - - -def time64_to_datetime(ndarray[int64_t, ndim=1] arr): - cdef int i, n - cdef ndarray[object, ndim=1] result - - n = len(arr) - result = np.empty(n, dtype=object) - - for i from 0 <= i < n: - result[i] = to_datetime(arr[i]) - - return result - +from tslibs.conversion import ( # noqa + time64_to_datetime, + array_to_timestamp, to_timestamp, to_datetime) +from tslibs.conversion cimport to_timestamp, to_datetime, gmtime # noqa #---------------------------------------------------------------------- # isnull / notnull related diff --git a/pandas/_libs/tslibs/conversion.pxd b/pandas/_libs/tslibs/conversion.pxd new file mode 100644 index 0000000000000..c81f530e0b25d --- /dev/null +++ b/pandas/_libs/tslibs/conversion.pxd @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# cython: profile=False + +from numpy cimport int64_t + +cdef int64_t gmtime(object date) +cpdef object to_datetime(int64_t timestamp) +cpdef object to_timestamp(object dt) + +cdef _to_i8(object val) diff --git a/pandas/_libs/tslibs/conversion.pyx b/pandas/_libs/tslibs/conversion.pyx new file mode 100644 index 0000000000000..62d9609bb77e8 --- /dev/null +++ b/pandas/_libs/tslibs/conversion.pyx @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +# cython: profile=False + + +from datetime import ( + date as pydate, + datetime as pydatetime) + +from cpython.datetime cimport ( + PyDateTime_Check, + PyDateTime_GET_YEAR, + PyDateTime_GET_MONTH, + PyDateTime_GET_DAY, + PyDateTime_DATE_GET_HOUR, + PyDateTime_DATE_GET_MINUTE, + PyDateTime_DATE_GET_SECOND, + PyDateTime_IMPORT) +PyDateTime_IMPORT + +from datetime cimport (get_datetime64_value, _pydatetime_to_dts, + pandas_datetimestruct) + +import numpy as np +cimport numpy as cnp +from numpy cimport int64_t, ndarray +cnp.import_array() + +cimport util + +from timezones cimport get_utcoffset, is_utc + +# ---------------------------------------------------------------------- +# Constants +cdef int _EPOCH_ORD = 719163 + +# ---------------------------------------------------------------------- +# Non-pandas-specific + +cpdef object to_datetime(int64_t timestamp): + return pydatetime.utcfromtimestamp(timestamp / 1000.0) + + +cdef inline int64_t gmtime(object date): + cdef int y, m, d, h, mn, s, days + + y = PyDateTime_GET_YEAR(date) + m = PyDateTime_GET_MONTH(date) + d = PyDateTime_GET_DAY(date) + h = PyDateTime_DATE_GET_HOUR(date) + mn = PyDateTime_DATE_GET_MINUTE(date) + s = PyDateTime_DATE_GET_SECOND(date) + + days = pydate(y, m, 1).toordinal() - _EPOCH_ORD + d - 1 + return (( (((days * 24 + h) * 60 + mn))) * 60 + s) * 1000 + + +cpdef object to_timestamp(object dt): + return gmtime(dt) + + +def array_to_timestamp(ndarray[object, ndim=1] arr): + cdef int i, n + cdef ndarray[int64_t, ndim=1] result + + n = len(arr) + result = np.empty(n, dtype=np.int64) + + for i in range(n): + result[i] = gmtime(arr[i]) + + return result + + +def time64_to_datetime(ndarray[int64_t, ndim=1] arr): + cdef int i, n + cdef ndarray[object, ndim=1] result + + n = len(arr) + result = np.empty(n, dtype=object) + + for i in range(n): + result[i] = to_datetime(arr[i]) + + return result + + +# ---------------------------------------------------------------------- + +cdef inline _to_i8(object val): + cdef pandas_datetimestruct dts + try: + return val.value + except AttributeError: + if util.is_datetime64_object(val): + return get_datetime64_value(val) + elif PyDateTime_Check(val): + tzinfo = getattr(val, 'tzinfo', None) + # Save the original date value so we can get the utcoffset from it. + ival = _pydatetime_to_dts(val, &dts) + if tzinfo is not None and not is_utc(tzinfo): + offset = get_utcoffset(tzinfo, val) + ival -= int(offset.total_seconds() * 1e9) + return ival + return val diff --git a/setup.py b/setup.py index d25ae4a5fb45c..b66f74126d26a 100755 --- a/setup.py +++ b/setup.py @@ -341,6 +341,7 @@ class CheckSDist(sdist_class): 'pandas/_libs/window.pyx', 'pandas/_libs/sparse.pyx', 'pandas/_libs/parsers.pyx', + 'pandas/_libs/tslibs/conversion.pyx', 'pandas/_libs/tslibs/timezones.pyx', 'pandas/_libs/tslibs/frequencies.pyx', 'pandas/_libs/tslibs/parsing.pyx', @@ -492,6 +493,7 @@ def pxd(name): 'depends': tseries_depends, 'sources': ['pandas/_libs/src/datetime/np_datetime.c', 'pandas/_libs/src/datetime/np_datetime_strings.c']}, + '_libs.tslibs.conversion': {'pyxfile': '_libs/tslibs/conversion'}, '_libs.tslibs.timezones': {'pyxfile': '_libs/tslibs/timezones'}, '_libs.period': {'pyxfile': '_libs/period', 'depends': (tseries_depends +