summaryrefslogtreecommitdiff
path: root/Cython/Includes/cpython/datetime.pxd
diff options
context:
space:
mode:
Diffstat (limited to 'Cython/Includes/cpython/datetime.pxd')
-rw-r--r--Cython/Includes/cpython/datetime.pxd262
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