Commit 14559510 authored by Bluenix's avatar Bluenix Committed by GitHub

Add missing declarations to datetime.pxd (GH-4128)

parent 1b98f7b1
from cpython.object cimport PyObject
from cpython.version cimport PY_VERSION_HEX
cdef extern from "Python.h":
ctypedef struct PyTypeObject:
......@@ -6,22 +7,88 @@ cdef extern from "Python.h":
cdef extern from "datetime.h":
"""
#if PY_MAJOR_VERSION < 3 && !defined(PyDateTime_DELTA_GET_DAYS)
/* 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
#if PY_MAJOR_VERSION < 3 && !defined(PyDateTime_DELTA_GET_SECONDS)
#ifndef PyDateTime_DELTA_GET_SECONDS
#define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds)
#endif
#if PY_MAJOR_VERSION < 3 && !defined(PyDateTime_DELTA_GET_MICROSECONDS)
#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
"""
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 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]:
@property
......@@ -52,8 +119,23 @@ cdef extern from "datetime.h":
cdef inline int microsecond(self):
return PyDateTime_DATE_GET_MICROSECOND(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
......@@ -62,10 +144,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
......@@ -84,14 +168,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)
......@@ -119,21 +216,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)
object PyDateTime_DATE_GET_TZINFO(object o)
# 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)
object PyDateTime_TIME_GET_TZINFO(object o)
# 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.
......@@ -143,29 +264,50 @@ 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:
......@@ -220,6 +362,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)
......@@ -236,6 +383,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
......
# coding: utf-8
from cpython.datetime cimport import_datetime
from cpython.datetime cimport date, time, datetime, timedelta, PyDateTime_IMPORT
from cpython.datetime cimport date, time, datetime, timedelta, timezone_new, PyDateTime_IMPORT
import sys
import_datetime()
......@@ -40,3 +42,20 @@ def test_timedelta(int days, int seconds, int useconds):
'''
val = timedelta(days, seconds, useconds)
return val
def test_timezone(int days, int seconds, int useconds, str name):
'''
>>> val = test_timezone(0, 3600, 0, 'CET')
>>> print(val)
True
'''
try:
val = timezone_new(timedelta(days, seconds, useconds), name)
except RuntimeError:
if sys.version_info < (3, 7):
return True
else:
# It's only supposed to raise on Python < 3.7
return False
else:
return True
# mode: run
# tag: datetime
import sys
from cpython.datetime cimport import_datetime
from cpython.datetime cimport time_new, date_new, datetime_new, timedelta_new
from cpython.datetime cimport datetime, time
from cpython.datetime cimport time_tzinfo, datetime_tzinfo
from cpython.datetime cimport time_hour, time_minute, time_second, time_microsecond
from cpython.datetime cimport time_hour, time_minute, time_second, time_microsecond, time_fold
from cpython.datetime cimport date_day, date_month, date_year
from cpython.datetime cimport datetime_day, datetime_month, datetime_year
from cpython.datetime cimport datetime_hour, datetime_minute, datetime_second, \
datetime_microsecond
datetime_microsecond, datetime_fold
from cpython.datetime cimport timedelta_days, timedelta_seconds, timedelta_microseconds
import_datetime()
......@@ -20,31 +26,39 @@ def test_date(int year, int month, int day):
o.month == date_month(o), \
o.day == date_day(o)
def test_datetime(int year, int month, int day,
int hour, int minute, int second, int microsecond):
def test_datetime(int year, int month, int day, int hour,
int minute, int second, int microsecond, int fold):
'''
>>> test_datetime(2012, 12, 31, 12, 30, 59, 12345)
(True, True, True, True, True, True, True)
>>> test_datetime(2012, 12, 31, 12, 30, 59, 12345, 0)
(True, True, True, True, True, True, True, True)
>>> test_datetime(2012, 12, 11, 12, 30, 59, 3322, 1 if sys.version_info >= (3, 7) else 0)
(True, True, True, True, True, True, True, True)
'''
o = datetime_new(year, month, day, hour, minute, second, microsecond, None)
o = datetime_new(
year, month, day, hour, minute, second, microsecond, None, fold
)
return o.year == datetime_year(o), \
o.month == datetime_month(o), \
o.day == datetime_day(o), \
o.hour == datetime_hour(o), \
o.minute == datetime_minute(o), \
o.second == datetime_second(o), \
o.microsecond == datetime_microsecond(o)
o.microsecond == datetime_microsecond(o), \
o.fold == datetime_fold(o)
def test_time(int hour, int minute, int second, int microsecond):
def test_time(int hour, int minute, int second, int microsecond, int fold):
'''
>>> test_time(12, 30, 59, 12345)
(True, True, True, True)
>>> test_time(12, 30, 59, 12345, 0)
(True, True, True, True, True)
>>> test_time(12, 30, 43, 5432, 1 if sys.version_info >= (3, 7) else 0)
(True, True, True, True, True)
'''
o = time_new(hour, minute, second, microsecond, None)
o = time_new(hour, minute, second, microsecond, None, fold)
return o.hour == time_hour(o), \
o.minute == time_minute(o), \
o.second == time_second(o), \
o.microsecond == time_microsecond(o)
o.microsecond == time_microsecond(o), \
o.fold == time_fold(o)
def test_timedelta(int days, int seconds, int microseconds):
'''
......@@ -55,4 +69,3 @@ def test_timedelta(int days, int seconds, int microseconds):
return o.days == timedelta_days(o), \
o.seconds == timedelta_seconds(o), \
o.microseconds == timedelta_microseconds(o)
......@@ -11,8 +11,9 @@ from cpython.datetime cimport datetime_day, datetime_month, datetime_year
from cpython.datetime cimport datetime_hour, datetime_minute, datetime_second, \
datetime_microsecond
from cpython.datetime cimport datetime, total_seconds
from cpython.datetime cimport date_from_timestamp, get_utc, datetime_from_timestamp
# These were added in Py3, make sure that their backport works.
# These were added in Python 2.7.5, make sure that their backport works.
from cpython.datetime cimport (
timedelta as timedelta_ext_type,
PyDateTime_DELTA_GET_DAYS,
......@@ -21,6 +22,8 @@ from cpython.datetime cimport (
)
import datetime as py_datetime
import time as py_time
import sys
import_datetime()
......@@ -238,3 +241,39 @@ def test_datetime_attrs_inlined(datetime dt):
dt.second,
dt.microsecond,
)
def test_date_from_timestamp():
"""
>>> from datetime import datetime
>>> tp, dt = test_date_from_timestamp()
>>> tp == dt
True
"""
tp = date_from_timestamp(1518185542)
dt = py_datetime.date(2018, 2, 9)
return tp, dt
def test_get_utc():
"""
>>> from datetime import datetime
>>> test_get_utc()
True
"""
try:
get_utc()
except RuntimeError:
if sys.version_info >= (3, 7):
raise # get_utc() is only supposed to raise on Python < 3.7
return True
def test_datetime_from_timestamp():
"""
>>> from datetime import datetime
>>> tp, dt = test_datetime_from_timestamp()
>>> tp == dt
True
"""
time = py_time.time()
tp = datetime_from_timestamp(time)
dt = py_datetime.datetime.fromtimestamp(time)
return tp, dt
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment