diff options
Diffstat (limited to 'Cython/Includes/cpython/datetime.pxd')
-rw-r--r-- | Cython/Includes/cpython/datetime.pxd | 262 |
1 files changed, 238 insertions, 24 deletions
diff --git a/Cython/Includes/cpython/datetime.pxd b/Cython/Includes/cpython/datetime.pxd index cd0f90719..7d6ee29f3 100644 --- a/Cython/Includes/cpython/datetime.pxd +++ b/Cython/Includes/cpython/datetime.pxd @@ -1,22 +1,161 @@ from cpython.object cimport PyObject +from cpython.version cimport PY_VERSION_HEX cdef extern from "Python.h": ctypedef struct PyTypeObject: pass cdef extern from "datetime.h": + """ + /* Backport for Python 2.x */ + #if PY_MAJOR_VERSION < 3 + #ifndef PyDateTime_DELTA_GET_DAYS + #define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days) + #endif + #ifndef PyDateTime_DELTA_GET_SECONDS + #define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds) + #endif + #ifndef PyDateTime_DELTA_GET_MICROSECONDS + #define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta*)o)->microseconds) + #endif + #endif + + /* Backport for Python < 3.6 */ + #if PY_VERSION_HEX < 0x030600a4 + #ifndef PyDateTime_TIME_GET_FOLD + #define PyDateTime_TIME_GET_FOLD(o) ((void)(o), 0) + #endif + #ifndef PyDateTime_DATE_GET_FOLD + #define PyDateTime_DATE_GET_FOLD(o) ((void)(o), 0) + #endif + #endif + + /* Backport for Python < 3.6 */ + #if PY_VERSION_HEX < 0x030600a4 + #define __Pyx_DateTime_DateTimeWithFold(year, month, day, hour, minute, second, microsecond, tz, fold) \ + ((void)(fold), PyDateTimeAPI->DateTime_FromDateAndTime(year, month, day, hour, minute, second, \ + microsecond, tz, PyDateTimeAPI->DateTimeType)) + #define __Pyx_DateTime_TimeWithFold(hour, minute, second, microsecond, tz, fold) \ + ((void)(fold), PyDateTimeAPI->Time_FromTime(hour, minute, second, microsecond, tz, PyDateTimeAPI->TimeType)) + #else /* For Python 3.6+ so that we can pass tz */ + #define __Pyx_DateTime_DateTimeWithFold(year, month, day, hour, minute, second, microsecond, tz, fold) \ + PyDateTimeAPI->DateTime_FromDateAndTimeAndFold(year, month, day, hour, minute, second, \ + microsecond, tz, fold, PyDateTimeAPI->DateTimeType) + #define __Pyx_DateTime_TimeWithFold(hour, minute, second, microsecond, tz, fold) \ + PyDateTimeAPI->Time_FromTimeAndFold(hour, minute, second, microsecond, tz, fold, PyDateTimeAPI->TimeType) + #endif + + /* Backport for Python < 3.7 */ + #if PY_VERSION_HEX < 0x030700b1 + #define __Pyx_TimeZone_UTC NULL + #define __Pyx_TimeZone_FromOffsetAndName(offset, name) ((void)(offset), (void)(name), (PyObject*)NULL) + #else + #define __Pyx_TimeZone_UTC PyDateTime_TimeZone_UTC + #define __Pyx_TimeZone_FromOffsetAndName(offset, name) PyTimeZone_FromOffsetAndName(offset, name) + #endif + + /* Backport for Python < 3.10 */ + #if PY_VERSION_HEX < 0x030a00a1 + #ifndef PyDateTime_TIME_GET_TZINFO + #define PyDateTime_TIME_GET_TZINFO(o) \ + ((((PyDateTime_Time*)o)->hastzinfo) ? ((PyDateTime_Time*)o)->tzinfo : Py_None) + #endif + #ifndef PyDateTime_DATE_GET_TZINFO + #define PyDateTime_DATE_GET_TZINFO(o) \ + ((((PyDateTime_DateTime*)o)->hastzinfo) ? ((PyDateTime_DateTime*)o)->tzinfo : Py_None) + #endif + #endif + """ ctypedef extern class datetime.date[object PyDateTime_Date]: - pass + @property + cdef inline int year(self): + return PyDateTime_GET_YEAR(self) + + @property + cdef inline int month(self): + return PyDateTime_GET_MONTH(self) + + @property + cdef inline int day(self): + return PyDateTime_GET_DAY(self) ctypedef extern class datetime.time[object PyDateTime_Time]: - pass + @property + cdef inline int hour(self): + return PyDateTime_TIME_GET_HOUR(self) + + @property + cdef inline int minute(self): + return PyDateTime_TIME_GET_MINUTE(self) + + @property + cdef inline int second(self): + return PyDateTime_TIME_GET_SECOND(self) + + @property + cdef inline int microsecond(self): + return PyDateTime_TIME_GET_MICROSECOND(self) + + @property + cdef inline object tzinfo(self): + return <object>PyDateTime_TIME_GET_TZINFO(self) + + @property + cdef inline int fold(self): + # For Python < 3.6 this returns 0 no matter what + return PyDateTime_TIME_GET_FOLD(self) ctypedef extern class datetime.datetime[object PyDateTime_DateTime]: - pass + @property + cdef inline int year(self): + return PyDateTime_GET_YEAR(self) + + @property + cdef inline int month(self): + return PyDateTime_GET_MONTH(self) + + @property + cdef inline int day(self): + return PyDateTime_GET_DAY(self) + + @property + cdef inline int hour(self): + return PyDateTime_DATE_GET_HOUR(self) + + @property + cdef inline int minute(self): + return PyDateTime_DATE_GET_MINUTE(self) + + @property + cdef inline int second(self): + return PyDateTime_DATE_GET_SECOND(self) + + @property + cdef inline int microsecond(self): + return PyDateTime_DATE_GET_MICROSECOND(self) + + @property + cdef inline object tzinfo(self): + return <object>PyDateTime_DATE_GET_TZINFO(self) + + @property + cdef inline int fold(self): + # For Python < 3.6 this returns 0 no matter what + return PyDateTime_DATE_GET_FOLD(self) ctypedef extern class datetime.timedelta[object PyDateTime_Delta]: - pass + @property + cdef inline int day(self): + return PyDateTime_DELTA_GET_DAYS(self) + + @property + cdef inline int second(self): + return PyDateTime_DELTA_GET_SECONDS(self) + + @property + cdef inline int microsecond(self): + return PyDateTime_DELTA_GET_MICROSECONDS(self) ctypedef extern class datetime.tzinfo[object PyDateTime_TZInfo]: pass @@ -25,10 +164,12 @@ cdef extern from "datetime.h": pass ctypedef struct PyDateTime_Time: + unsigned char fold char hastzinfo PyObject *tzinfo ctypedef struct PyDateTime_DateTime: + unsigned char fold char hastzinfo PyObject *tzinfo @@ -47,14 +188,27 @@ cdef extern from "datetime.h": PyTypeObject *TZInfoType # constructors - object (*Date_FromDate)(int, int, int, PyTypeObject*) - object (*DateTime_FromDateAndTime)(int, int, int, int, int, int, int, object, PyTypeObject*) - object (*Time_FromTime)(int, int, int, int, object, PyTypeObject*) - object (*Delta_FromDelta)(int, int, int, int, PyTypeObject*) + date (*Date_FromDate)(int, int, int, PyTypeObject*) + datetime (*DateTime_FromDateAndTime)(int, int, int, int, int, int, int, object, PyTypeObject*) + time (*Time_FromTime)(int, int, int, int, object, PyTypeObject*) + timedelta (*Delta_FromDelta)(int, int, int, int, PyTypeObject*) # constructors for the DB API - object (*DateTime_FromTimestamp)(object, object, object) - object (*Date_FromTimestamp)(object, object) + datetime (*DateTime_FromTimestamp)(PyObject*, object, PyObject*) + date (*Date_FromTimestamp)(PyObject*, object) + + # We cannot use the following because they do not compile in older Python versions. + # Instead, we use datetime.h's macros here that we can backport in C. + + # Python 3.7+ constructors + object (*TimeZone_FromTimeZone)(object offset, PyObject *name) + + # Python 3.7+ singletons + PyObject *TimeZone_UTC + + # Python 3.6+ PEP 495 constructors + datetime (*DateTime_FromDateAndTimeAndFold)(int, int, int, int, int, int, int, object, int, PyTypeObject*) + time (*Time_FromTimeAndFold)(int, int, int ,int, object, int, PyTypeObject*) # Check type of the object. bint PyDate_Check(object op) @@ -82,21 +236,45 @@ cdef extern from "datetime.h": int PyDateTime_DATE_GET_MINUTE(object o) int PyDateTime_DATE_GET_SECOND(object o) int PyDateTime_DATE_GET_MICROSECOND(object o) + int PyDateTime_DATE_GET_FOLD(object o) + PyObject* PyDateTime_DATE_GET_TZINFO(object o) # returns a borrowed reference # Getters for time (C macros). int PyDateTime_TIME_GET_HOUR(object o) int PyDateTime_TIME_GET_MINUTE(object o) int PyDateTime_TIME_GET_SECOND(object o) int PyDateTime_TIME_GET_MICROSECOND(object o) + int PyDateTime_TIME_GET_FOLD(object o) + PyObject* PyDateTime_TIME_GET_TZINFO(object o) # returns a borrowed reference # Getters for timedelta (C macros). int PyDateTime_DELTA_GET_DAYS(object o) int PyDateTime_DELTA_GET_SECONDS(object o) int PyDateTime_DELTA_GET_MICROSECONDS(object o) + # Constructors + object PyTimeZone_FromOffset(object offset) + object PyTimeZone_FromOffsetAndName(object offset, object name) + + # The above macros is Python 3.7+ so we use these instead + object __Pyx_TimeZone_FromOffsetAndName(object offset, PyObject* name) + + # Constructors for the DB API + datetime PyDateTime_FromTimeStamp(object args) + date PyDate_FromTimeStamp(object args) + + # PEP 495 constructors but patched above to allow passing tz + datetime __Pyx_DateTime_DateTimeWithFold(int, int, int, int, int, int, int, object, int) + datetime __Pyx_DateTime_TimeWithFold(int, int, int ,int, object, int) + # PyDateTime CAPI object. PyDateTime_CAPI *PyDateTimeAPI + PyObject* PyDateTime_TimeZone_UTC + + # PyDateTime_TimeZone_UTC is Python 3.7+ so instead we use the following macro + PyObject* __Pyx_TimeZone_UTC + void PyDateTime_IMPORT() # Datetime C API initialization function. @@ -106,42 +284,57 @@ cdef inline void import_datetime(): # Create date object using DateTime CAPI factory function. # Note, there are no range checks for any of the arguments. -cdef inline object date_new(int year, int month, int day): +cdef inline date date_new(int year, int month, int day): return PyDateTimeAPI.Date_FromDate(year, month, day, PyDateTimeAPI.DateType) # Create time object using DateTime CAPI factory function # Note, there are no range checks for any of the arguments. -cdef inline object time_new(int hour, int minute, int second, int microsecond, object tz): - return PyDateTimeAPI.Time_FromTime(hour, minute, second, microsecond, tz, PyDateTimeAPI.TimeType) +cdef inline time time_new(int hour, int minute, int second, int microsecond, object tz, int fold=0): + return __Pyx_DateTime_TimeWithFold(hour, minute, second, microsecond, tz, fold) # Create datetime object using DateTime CAPI factory function. # Note, there are no range checks for any of the arguments. -cdef inline object datetime_new(int year, int month, int day, int hour, int minute, int second, int microsecond, object tz): - return PyDateTimeAPI.DateTime_FromDateAndTime(year, month, day, hour, minute, second, microsecond, tz, PyDateTimeAPI.DateTimeType) +cdef inline datetime datetime_new(int year, int month, int day, int hour, int minute, int second, int microsecond, object tz, int fold=0): + return __Pyx_DateTime_DateTimeWithFold(year, month, day, hour, minute, second, microsecond, tz, fold) # Create timedelta object using DateTime CAPI factory function. # Note, there are no range checks for any of the arguments. -cdef inline object timedelta_new(int days, int seconds, int useconds): +cdef inline timedelta timedelta_new(int days, int seconds, int useconds): return PyDateTimeAPI.Delta_FromDelta(days, seconds, useconds, 1, PyDateTimeAPI.DeltaType) +# Create timedelta object using DateTime CAPI factory function. +cdef inline object timezone_new(object offset, object name=None): + if PY_VERSION_HEX < 0x030700b1: + raise RuntimeError('Time zones are not available from the C-API.') + return __Pyx_TimeZone_FromOffsetAndName(offset, <PyObject*>name if name is not None else NULL) + +# Create datetime object using DB API constructor. +cdef inline datetime datetime_from_timestamp(timestamp, tz=None): + return PyDateTimeAPI.DateTime_FromTimestamp( + <PyObject*>PyDateTimeAPI.DateTimeType, (timestamp, tz) if tz is not None else (timestamp,), NULL) + +# Create date object using DB API constructor. +cdef inline date date_from_timestamp(timestamp): + return PyDateTimeAPI.Date_FromTimestamp(<PyObject*>PyDateTimeAPI.DateType, (timestamp,)) + # More recognizable getters for date/time/datetime/timedelta. # There are no setters because datetime.h hasn't them. # This is because of immutable nature of these objects by design. # If you would change time/date/datetime/timedelta object you need to recreate. +# Get UTC singleton +cdef inline object get_utc(): + if PY_VERSION_HEX < 0x030700b1: + raise RuntimeError('Time zones are not available from the C-API.') + return <object>__Pyx_TimeZone_UTC + # Get tzinfo of time cdef inline object time_tzinfo(object o): - if (<PyDateTime_Time*>o).hastzinfo: - return <object>(<PyDateTime_Time*>o).tzinfo - else: - return None + return <object>PyDateTime_TIME_GET_TZINFO(o) # Get tzinfo of datetime cdef inline object datetime_tzinfo(object o): - if (<PyDateTime_DateTime*>o).hastzinfo: - return <object>(<PyDateTime_DateTime*>o).tzinfo - else: - return None + return <object>PyDateTime_DATE_GET_TZINFO(o) # Get year of date cdef inline int date_year(object o): @@ -183,6 +376,11 @@ cdef inline int time_second(object o): cdef inline int time_microsecond(object o): return PyDateTime_TIME_GET_MICROSECOND(o) +# Get fold of time +cdef inline int time_fold(object o): + # For Python < 3.6 this returns 0 no matter what + return PyDateTime_TIME_GET_FOLD(o) + # Get hour of datetime cdef inline int datetime_hour(object o): return PyDateTime_DATE_GET_HOUR(o) @@ -199,6 +397,11 @@ cdef inline int datetime_second(object o): cdef inline int datetime_microsecond(object o): return PyDateTime_DATE_GET_MICROSECOND(o) +# Get fold of datetime +cdef inline int datetime_fold(object o): + # For Python < 3.6 this returns 0 no matter what + return PyDateTime_DATE_GET_FOLD(o) + # Get days of timedelta cdef inline int timedelta_days(object o): return (<PyDateTime_Delta*>o).days @@ -210,3 +413,14 @@ cdef inline int timedelta_seconds(object o): # Get microseconds of timedelta cdef inline int timedelta_microseconds(object o): return (<PyDateTime_Delta*>o).microseconds + +cdef inline double total_seconds(timedelta obj): + # Mirrors the "timedelta.total_seconds()" method. + # Note that this implementation is not guaranteed to give *exactly* the same + # result as the original method, due to potential differences in floating point rounding. + cdef: + double days, seconds, micros + days = <double>PyDateTime_DELTA_GET_DAYS(obj) + seconds = <double>PyDateTime_DELTA_GET_SECONDS(obj) + micros = <double>PyDateTime_DELTA_GET_MICROSECONDS(obj) + return days * 24 * 3600 + seconds + micros / 1_000_000 |