From 26fa0ddd094997b2305e31c145917a25dee725b5 Mon Sep 17 00:00:00 2001
From: zaur <aintellimath@gmail.com>
Date: Wed, 27 Feb 2013 12:46:26 +0300
Subject: [PATCH] Add datetime.pxd to cython.cpython. Part II

---
 Cython/Includes/cpython/__init__.pxd |   2 +
 Cython/Includes/cpython/datetime.pxd | 206 +++++++++++++++++++++++++++
 tests/run/datetime_cimport.pyx       |  43 ++++++
 tests/run/datetime_pxd.pyx           | 173 ++++++++++++++++++++++
 4 files changed, 424 insertions(+)
 create mode 100644 Cython/Includes/cpython/datetime.pxd
 create mode 100644 tests/run/datetime_cimport.pyx
 create mode 100644 tests/run/datetime_pxd.pyx

diff --git a/Cython/Includes/cpython/__init__.pxd b/Cython/Includes/cpython/__init__.pxd
index 27c11604d..22b928e6d 100644
--- a/Cython/Includes/cpython/__init__.pxd
+++ b/Cython/Includes/cpython/__init__.pxd
@@ -182,3 +182,5 @@ from cpython.pycapsule cimport *
 #################################################################
 # END OF DEPRECATED SECTION
 #################################################################
+
+from cpython.datetime cimport *
diff --git a/Cython/Includes/cpython/datetime.pxd b/Cython/Includes/cpython/datetime.pxd
new file mode 100644
index 000000000..913d86414
--- /dev/null
+++ b/Cython/Includes/cpython/datetime.pxd
@@ -0,0 +1,206 @@
+from cpython.ref cimport PyObject
+
+cdef extern from "Python.h":
+    ctypedef struct PyTypeObject:
+        pass
+
+cdef extern from "datetime.h":
+    
+    ctypedef extern class datetime.date[object PyDateTime_Date]:
+        pass
+
+    ctypedef extern class datetime.time[object PyDateTime_Time]:
+        pass
+
+    ctypedef extern class datetime.datetime[object PyDateTime_DateTime]:
+        pass
+
+    ctypedef extern class datetime.timedelta[object PyDateTime_Delta]:
+        pass
+
+    ctypedef extern class datetime.tzinfo[object PyDateTime_TZInfo]:
+        pass
+
+    ctypedef struct PyDateTime_Date:
+        pass
+    
+    ctypedef struct PyDateTime_Time:
+        char hastzinfo             # boolean flag
+        PyObject *tzinfo
+        
+    ctypedef struct PyDateTime_DateTime:
+        char hastzinfo             # boolean flag
+        PyObject *tzinfo
+        
+    # Define structure for C API.
+    ctypedef struct PyDateTime_CAPI:
+        long hashcode
+        # type objects 
+        PyTypeObject *DateType
+        PyTypeObject *DateTimeType
+        PyTypeObject *TimeType
+        PyTypeObject *DeltaType
+        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*)
+    
+        # constructors for the DB API
+        object (*DateTime_FromTimestamp)(object, object, object)
+        object (*Date_FromTimestamp)(object, object)
+
+    # Check type of the object.
+    bint PyDate_Check(object op)
+    bint PyDate_CheckExact(object op)
+
+    bint PyDateTime_Check(object op)
+    bint PyDateTime_CheckExact(object op)
+
+    bint PyTime_Check(object op)
+    bint PyTime_CheckExact(object op)
+
+    bint PyDelta_Check(object op)
+    bint PyDelta_CheckExact(object op)
+
+    bint PyTZInfo_Check(object op)
+    bint PyTZInfo_CheckExact(object op)
+
+    # Getters for date and datetime (C macros).
+    int PyDateTime_GET_YEAR(object o)
+    int PyDateTime_GET_MONTH(object o)
+    int PyDateTime_GET_DAY(object o)
+
+    # Getters for datetime (C macros).
+    int PyDateTime_DATE_GET_HOUR(object o)
+    int PyDateTime_DATE_GET_MINUTE(object o)
+    int PyDateTime_DATE_GET_SECOND(object o)
+    int PyDateTime_DATE_GET_MICROSECOND(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)
+
+    # 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)
+
+    # PyDateTime CAPI object.
+    PyDateTime_CAPI *PyDateTimeAPI
+    
+    # Datetime C API object initialization C macros.
+    # You have to call this before any usage of DateTime CAPI functions:
+    #   PyDateTime_IMPORT
+    void PyDateTime_IMPORT()
+
+# 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):
+    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)
+
+# 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)
+
+# 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):
+    return PyDateTimeAPI.Delta_FromDelta(days, seconds, useconds, 1, PyDateTimeAPI.DeltaType)
+
+#
+# More recognizable getters for date/time/datetime/timedelta.
+# There are no setters because datetime.h didn't exposed them.
+# 
+
+# 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
+
+# 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
+
+# Get year of date
+cdef inline int date_year(object o):
+    return PyDateTime_GET_YEAR(o)
+    
+# Get month of date
+cdef inline int date_month(object o):
+    return PyDateTime_GET_MONTH(o)
+
+# Get day of date
+cdef inline int date_day(object o):
+    return PyDateTime_GET_DAY(o)
+
+# Get year of datetime
+cdef inline int datetime_year(object o):
+    return PyDateTime_GET_YEAR(o)
+    
+# Get month of datetime
+cdef inline int datetime_month(object o):
+    return PyDateTime_GET_MONTH(o)
+
+# Get day of datetime
+cdef inline int datetime_day(object o):
+    return PyDateTime_GET_DAY(o)
+
+# Get hour of time
+cdef inline int time_hour(object o):
+    return PyDateTime_TIME_GET_HOUR(o)
+
+# Get minute of time
+cdef inline int time_minute(object o):
+    return PyDateTime_TIME_GET_MINUTE(o)
+
+# Get second of time
+cdef inline int time_second(object o):
+    return PyDateTime_TIME_GET_SECOND(o)
+
+# Get microsecond of time
+cdef inline int time_microsecond(object o):
+    return PyDateTime_TIME_GET_MICROSECOND(o)
+
+# Get hour of datetime
+cdef inline int datetime_hour(object o):
+    return PyDateTime_DATE_GET_HOUR(o)
+
+# Get minute of datetime
+cdef inline int datetime_minute(object o):
+    return PyDateTime_DATE_GET_MINUTE(o)
+
+# Get second of datetime
+cdef inline int datetime_second(object o):
+    return PyDateTime_DATE_GET_SECOND(o)
+
+# Get microsecond of datetime
+cdef inline int datetime_microsecond(object o):
+    return PyDateTime_DATE_GET_MICROSECOND(o)
+
+# Get days of timedelta
+cdef inline int timedelta_days(object o):
+    return PyDateTime_DELTA_GET_DAYS(o)
+
+# Get seconds of timedelta
+cdef inline int timedelta_seconds(object o):
+    return PyDateTime_DELTA_GET_SECONDS(o)
+
+# Get microseconds of timedelta
+cdef inline int timedelta_microseconds(object o):
+    return PyDateTime_DELTA_GET_MICROSECONDS(o)
diff --git a/tests/run/datetime_cimport.pyx b/tests/run/datetime_cimport.pyx
new file mode 100644
index 000000000..af3efd932
--- /dev/null
+++ b/tests/run/datetime_cimport.pyx
@@ -0,0 +1,43 @@
+# coding: utf-8
+
+#import datetime
+from cpython.datetime cimport date, time, datetime, timedelta, PyDateTime_IMPORT
+
+PyDateTime_IMPORT
+        
+def test_date(int year, int month, int day):
+    '''
+    >>> val = test_date(2012, 12, 31)
+    >>> print(val)
+    2012-12-31
+    '''
+    val = date(year, month, day)
+    return val
+
+def test_time(int hour, int minute, int second, int microsecond):
+    '''
+    >>> val = test_time(12, 20, 55, 0)
+    >>> print(val)
+    12:20:55
+    '''
+    val = time(hour, minute, second, microsecond)
+    return val
+
+def test_datetime(int year, int month, int day, int hour, int minute, int second, int microsecond):
+    '''
+    >>> val = test_datetime(2012, 12, 31, 12, 20, 55, 0)
+    >>> print(val)
+    2012-12-31 12:20:55
+    '''
+    val = datetime(year, month, day, hour, minute, second, microsecond)
+    return val
+
+def test_timedelta(int days, int seconds, int useconds):
+    '''
+    >>> val = test_timedelta(30, 0, 0)
+    >>> print(val)
+    30 days, 0:00:00
+    '''
+    val = timedelta(days, seconds, useconds)
+    return val
+            
\ No newline at end of file
diff --git a/tests/run/datetime_pxd.pyx b/tests/run/datetime_pxd.pyx
new file mode 100644
index 000000000..99b7937db
--- /dev/null
+++ b/tests/run/datetime_pxd.pyx
@@ -0,0 +1,173 @@
+# coding: utf-8
+
+#cimport cpython.datetime as cy_datetime
+#from datetime import time, date, datetime, timedelta, tzinfo
+
+
+from cpython.datetime cimport PyDateTime_IMPORT
+from cpython.datetime cimport time_new, date_new, datetime_new, timedelta_new
+from cpython.datetime cimport time_tzinfo, datetime_tzinfo
+from cpython.datetime cimport time_hour, time_minute, time_second, time_microsecond
+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
+
+import datetime as py_datetime
+
+PyDateTime_IMPORT
+
+ZERO = py_datetime.timedelta(0)
+
+#
+# Simple class from datetime docs
+#
+class FixedOffset(py_datetime.tzinfo):
+    """Fixed offset in minutes east from UTC."""
+
+    def __init__(self, offset, name):
+        self._offset = py_datetime.timedelta(minutes = offset)
+        self._name = name
+
+    def utcoffset(self, dt):
+        return self._offset
+
+    def tzname(self, dt):
+        return self._name
+
+    def dst(self, dt):
+        return ZERO
+        
+def do_date(int year, int month, int day):
+    """
+    >>> do_date(2012, 12, 31)
+    (True, True, True, True)
+    """
+    v = date_new(year, month, day)
+    return type(v) is py_datetime.date, v.year == year, v.month == month, v.day == day
+
+def do_datetime(int year, int month, int day, 
+        int hour, int minute, int second, int microsecond):
+    """
+    >>> do_datetime(2012, 12, 31, 12, 23, 0, 0)
+    (True, True, True, True, True, True, True, True, True)
+    """
+    v = datetime_new(year, month, day, hour, minute, second, microsecond, None)
+    return type(v) is py_datetime.datetime, v.year == year, v.month == month, v.day == day, \
+           v.hour == hour, v.minute == minute, v.second == second, \
+           v.microsecond == microsecond, v.tzinfo is None
+
+def do_time(int hour, int minute, int second, int microsecond):
+    """
+    >>> do_time(12, 23, 0, 0)
+    (True, True, True, True, True, True)
+    """
+    v = time_new(hour, minute, second, microsecond, None)
+    return type(v) is py_datetime.time, \
+           v.hour == hour, v.minute == minute, v.second == second, \
+           v.microsecond == microsecond, v.tzinfo is None
+
+def do_time_tzinfo(int hour, int minute, int second, int microsecond, object tz):
+    """
+    >>> tz = FixedOffset(60*3, 'Moscow')    
+    >>> do_time_tzinfo(12, 23, 0, 0, tz)
+    (True, True, True, True, True, True)
+    """
+    v = time_new(hour, minute, second, microsecond, tz)
+    return type(v) is py_datetime.time, \
+           v.hour == hour, v.minute == minute, v.second == second, \
+           v.microsecond == microsecond, v.tzinfo is tz
+
+
+def do_datetime_tzinfo(int year, int month, int day, 
+        int hour, int minute, int second, int microsecond, object tz):
+    """
+    >>> tz = FixedOffset(60*3, 'Moscow')    
+    >>> do_datetime_tzinfo(2012, 12, 31, 12, 23, 0, 0, tz)
+    (True, True, True, True, True, True, True, True, True)
+    """
+    v = datetime_new(year, month, day, hour, minute, second, microsecond, tz)
+    return type(v) is py_datetime.datetime, v.year == year, v.month == month, v.day == day, \
+           v.hour == hour, v.minute == minute, v.second == second, \
+           v.microsecond == microsecond, v.tzinfo is tz
+           
+def do_time_tzinfo2(int hour, int minute, int second, int microsecond, object tz):
+    """
+    >>> tz = FixedOffset(60*3, 'Moscow')    
+    >>> do_time_tzinfo2(12, 23, 0, 0, tz)
+    (True, True, True, True, True, True, True, True)
+    """
+    v = time_new(hour, minute, second, microsecond, None)
+    v1 = time_new(
+            time_hour(v), 
+            time_minute(v), 
+            time_second(v), 
+            time_microsecond(v), 
+            tz)
+    r1 = (v1.tzinfo == tz)
+    r2 = (tz == time_tzinfo(v1))
+    v2 = time_new(
+            time_hour(v1), 
+            time_minute(v1), 
+            time_second(v1), 
+            time_microsecond(v1), 
+            None)
+    r3 = (v2.tzinfo == None)
+    r4 = (None == time_tzinfo(v2))
+    v3 = time_new(
+            time_hour(v2), 
+            time_minute(v2), 
+            time_second(v2), 
+            time_microsecond(v2), 
+            tz)
+    r5 = (v3.tzinfo == tz)
+    r6 = (tz == time_tzinfo(v3))
+    r7 = (v2 == v)
+    r8 = (v3 == v1)
+    return r1, r2, r3, r4, r5, r6, r7, r8
+
+
+def do_datetime_tzinfo2(int year, int month, int day,
+                              int hour, int minute, int second, int microsecond, object tz):
+    """
+    >>> tz = FixedOffset(60*3, 'Moscow')    
+    >>> do_datetime_tzinfo2(2012, 12, 31, 12, 23, 0, 0, tz)
+    (True, True, True, True, True, True, True, True)
+    """
+    v = datetime_new(year, month, day, hour, minute, second, microsecond, None)
+    v1 = datetime_new(
+            datetime_year(v), 
+            datetime_month(v), 
+            datetime_day(v), 
+            datetime_hour(v), 
+            datetime_minute(v), 
+            datetime_second(v), 
+            datetime_microsecond(v), 
+            tz)
+    r1 = (v1.tzinfo == tz)
+    r2 = (tz == datetime_tzinfo(v1))
+    v2 = datetime_new(
+            datetime_year(v1), 
+            datetime_month(v1), 
+            datetime_day(v1), 
+            datetime_hour(v1), 
+            datetime_minute(v1), 
+            datetime_second(v1), 
+            datetime_microsecond(v1), 
+            None)
+    r3 = (v2.tzinfo == None)
+    r4 = (None == datetime_tzinfo(v2))
+    v3 = datetime_new(
+            datetime_year(v2), 
+            datetime_month(v2), 
+            datetime_day(v2), 
+            datetime_hour(v2), 
+            datetime_minute(v2), 
+            datetime_second(v2), 
+            datetime_microsecond(v2), 
+            tz)
+    r5 = (v3.tzinfo == tz)
+    r6 = (tz == datetime_tzinfo(v3))
+    r7 = (v2 == v)
+    r8 = (v3 == v1)
+    return r1, r2, r3, r4, r5, r6, r7, r8
-- 
2.30.9