| #include "parts.h" |
| |
| #include "datetime.h" // PyDateTimeAPI |
| |
| |
| static int test_run_counter = 0; |
| |
| static PyObject * |
| test_datetime_capi(PyObject *self, PyObject *args) |
| { |
| if (PyDateTimeAPI) { |
| if (test_run_counter) { |
| /* Probably regrtest.py -R */ |
| Py_RETURN_NONE; |
| } |
| else { |
| PyErr_SetString(PyExc_AssertionError, |
| "PyDateTime_CAPI somehow initialized"); |
| return NULL; |
| } |
| } |
| test_run_counter++; |
| PyDateTime_IMPORT; |
| |
| if (PyDateTimeAPI) { |
| Py_RETURN_NONE; |
| } |
| return NULL; |
| } |
| |
| /* Functions exposing the C API type checking for testing */ |
| #define MAKE_DATETIME_CHECK_FUNC(check_method, exact_method) \ |
| do { \ |
| PyObject *obj; \ |
| int exact = 0; \ |
| if (!PyArg_ParseTuple(args, "O|p", &obj, &exact)) { \ |
| return NULL; \ |
| } \ |
| int rv = exact?exact_method(obj):check_method(obj); \ |
| if (rv) { \ |
| Py_RETURN_TRUE; \ |
| } \ |
| Py_RETURN_FALSE; \ |
| } while (0) \ |
| |
| static PyObject * |
| datetime_check_date(PyObject *self, PyObject *args) |
| { |
| MAKE_DATETIME_CHECK_FUNC(PyDate_Check, PyDate_CheckExact); |
| } |
| |
| static PyObject * |
| datetime_check_time(PyObject *self, PyObject *args) |
| { |
| MAKE_DATETIME_CHECK_FUNC(PyTime_Check, PyTime_CheckExact); |
| } |
| |
| static PyObject * |
| datetime_check_datetime(PyObject *self, PyObject *args) |
| { |
| MAKE_DATETIME_CHECK_FUNC(PyDateTime_Check, PyDateTime_CheckExact); |
| } |
| |
| static PyObject * |
| datetime_check_delta(PyObject *self, PyObject *args) |
| { |
| MAKE_DATETIME_CHECK_FUNC(PyDelta_Check, PyDelta_CheckExact); |
| } |
| |
| static PyObject * |
| datetime_check_tzinfo(PyObject *self, PyObject *args) |
| { |
| MAKE_DATETIME_CHECK_FUNC(PyTZInfo_Check, PyTZInfo_CheckExact); |
| } |
| #undef MAKE_DATETIME_CHECK_FUNC |
| |
| |
| /* Makes three variations on timezone representing UTC-5: |
| 1. timezone with offset and name from PyDateTimeAPI |
| 2. timezone with offset and name from PyTimeZone_FromOffsetAndName |
| 3. timezone with offset (no name) from PyTimeZone_FromOffset |
| */ |
| static PyObject * |
| make_timezones_capi(PyObject *self, PyObject *args) |
| { |
| PyObject *offset = PyDelta_FromDSU(0, -18000, 0); |
| PyObject *name = PyUnicode_FromString("EST"); |
| if (offset == NULL || name == NULL) { |
| Py_XDECREF(offset); |
| Py_XDECREF(name); |
| return NULL; |
| } |
| |
| PyObject *est_zone_capi = PyDateTimeAPI->TimeZone_FromTimeZone(offset, name); |
| PyObject *est_zone_macro = PyTimeZone_FromOffsetAndName(offset, name); |
| PyObject *est_zone_macro_noname = PyTimeZone_FromOffset(offset); |
| Py_DECREF(offset); |
| Py_DECREF(name); |
| if (est_zone_capi == NULL || est_zone_macro == NULL || |
| est_zone_macro_noname == NULL) |
| { |
| goto error; |
| } |
| PyObject *rv = PyTuple_New(3); |
| if (rv == NULL) { |
| goto error; |
| } |
| |
| PyTuple_SET_ITEM(rv, 0, est_zone_capi); |
| PyTuple_SET_ITEM(rv, 1, est_zone_macro); |
| PyTuple_SET_ITEM(rv, 2, est_zone_macro_noname); |
| |
| return rv; |
| error: |
| Py_XDECREF(est_zone_capi); |
| Py_XDECREF(est_zone_macro); |
| Py_XDECREF(est_zone_macro_noname); |
| return NULL; |
| } |
| |
| static PyObject * |
| get_timezones_offset_zero(PyObject *self, PyObject *args) |
| { |
| PyObject *offset = PyDelta_FromDSU(0, 0, 0); |
| PyObject *name = PyUnicode_FromString(""); |
| if (offset == NULL || name == NULL) { |
| Py_XDECREF(offset); |
| Py_XDECREF(name); |
| return NULL; |
| } |
| |
| // These two should return the UTC singleton |
| PyObject *utc_singleton_0 = PyTimeZone_FromOffset(offset); |
| PyObject *utc_singleton_1 = PyTimeZone_FromOffsetAndName(offset, NULL); |
| |
| // This one will return +00:00 zone, but not the UTC singleton |
| PyObject *non_utc_zone = PyTimeZone_FromOffsetAndName(offset, name); |
| Py_DECREF(offset); |
| Py_DECREF(name); |
| if (utc_singleton_0 == NULL || utc_singleton_1 == NULL || |
| non_utc_zone == NULL) |
| { |
| goto error; |
| } |
| |
| PyObject *rv = PyTuple_New(3); |
| if (rv == NULL) { |
| goto error; |
| } |
| PyTuple_SET_ITEM(rv, 0, utc_singleton_0); |
| PyTuple_SET_ITEM(rv, 1, utc_singleton_1); |
| PyTuple_SET_ITEM(rv, 2, non_utc_zone); |
| |
| return rv; |
| error: |
| Py_XDECREF(utc_singleton_0); |
| Py_XDECREF(utc_singleton_1); |
| Py_XDECREF(non_utc_zone); |
| return NULL; |
| } |
| |
| static PyObject * |
| get_timezone_utc_capi(PyObject *self, PyObject *args) |
| { |
| int macro = 0; |
| if (!PyArg_ParseTuple(args, "|p", ¯o)) { |
| return NULL; |
| } |
| if (macro) { |
| return Py_NewRef(PyDateTime_TimeZone_UTC); |
| } |
| return Py_NewRef(PyDateTimeAPI->TimeZone_UTC); |
| } |
| |
| static PyObject * |
| get_date_fromdate(PyObject *self, PyObject *args) |
| { |
| PyObject *rv = NULL; |
| int macro; |
| int year, month, day; |
| |
| if (!PyArg_ParseTuple(args, "piii", ¯o, &year, &month, &day)) { |
| return NULL; |
| } |
| |
| if (macro) { |
| rv = PyDate_FromDate(year, month, day); |
| } |
| else { |
| rv = PyDateTimeAPI->Date_FromDate( |
| year, month, day, |
| PyDateTimeAPI->DateType); |
| } |
| return rv; |
| } |
| |
| static PyObject * |
| get_datetime_fromdateandtime(PyObject *self, PyObject *args) |
| { |
| PyObject *rv = NULL; |
| int macro; |
| int year, month, day; |
| int hour, minute, second, microsecond; |
| |
| if (!PyArg_ParseTuple(args, "piiiiiii", |
| ¯o, |
| &year, &month, &day, |
| &hour, &minute, &second, µsecond)) { |
| return NULL; |
| } |
| |
| if (macro) { |
| rv = PyDateTime_FromDateAndTime( |
| year, month, day, |
| hour, minute, second, microsecond); |
| } |
| else { |
| rv = PyDateTimeAPI->DateTime_FromDateAndTime( |
| year, month, day, |
| hour, minute, second, microsecond, |
| Py_None, |
| PyDateTimeAPI->DateTimeType); |
| } |
| return rv; |
| } |
| |
| static PyObject * |
| get_datetime_fromdateandtimeandfold(PyObject *self, PyObject *args) |
| { |
| PyObject *rv = NULL; |
| int macro; |
| int year, month, day; |
| int hour, minute, second, microsecond, fold; |
| |
| if (!PyArg_ParseTuple(args, "piiiiiiii", |
| ¯o, |
| &year, &month, &day, |
| &hour, &minute, &second, µsecond, |
| &fold)) { |
| return NULL; |
| } |
| |
| if (macro) { |
| rv = PyDateTime_FromDateAndTimeAndFold( |
| year, month, day, |
| hour, minute, second, microsecond, |
| fold); |
| } |
| else { |
| rv = PyDateTimeAPI->DateTime_FromDateAndTimeAndFold( |
| year, month, day, |
| hour, minute, second, microsecond, |
| Py_None, |
| fold, |
| PyDateTimeAPI->DateTimeType); |
| } |
| return rv; |
| } |
| |
| static PyObject * |
| get_time_fromtime(PyObject *self, PyObject *args) |
| { |
| PyObject *rv = NULL; |
| int macro; |
| int hour, minute, second, microsecond; |
| |
| if (!PyArg_ParseTuple(args, "piiii", |
| ¯o, |
| &hour, &minute, &second, µsecond)) |
| { |
| return NULL; |
| } |
| |
| if (macro) { |
| rv = PyTime_FromTime(hour, minute, second, microsecond); |
| } |
| else { |
| rv = PyDateTimeAPI->Time_FromTime( |
| hour, minute, second, microsecond, |
| Py_None, |
| PyDateTimeAPI->TimeType); |
| } |
| return rv; |
| } |
| |
| static PyObject * |
| get_time_fromtimeandfold(PyObject *self, PyObject *args) |
| { |
| PyObject *rv = NULL; |
| int macro; |
| int hour, minute, second, microsecond, fold; |
| |
| if (!PyArg_ParseTuple(args, "piiiii", |
| ¯o, |
| &hour, &minute, &second, µsecond, |
| &fold)) { |
| return NULL; |
| } |
| |
| if (macro) { |
| rv = PyTime_FromTimeAndFold(hour, minute, second, microsecond, fold); |
| } |
| else { |
| rv = PyDateTimeAPI->Time_FromTimeAndFold( |
| hour, minute, second, microsecond, |
| Py_None, |
| fold, |
| PyDateTimeAPI->TimeType); |
| } |
| return rv; |
| } |
| |
| static PyObject * |
| get_delta_fromdsu(PyObject *self, PyObject *args) |
| { |
| PyObject *rv = NULL; |
| int macro; |
| int days, seconds, microseconds; |
| |
| if (!PyArg_ParseTuple(args, "piii", |
| ¯o, |
| &days, &seconds, µseconds)) { |
| return NULL; |
| } |
| |
| if (macro) { |
| rv = PyDelta_FromDSU(days, seconds, microseconds); |
| } |
| else { |
| rv = PyDateTimeAPI->Delta_FromDelta( |
| days, seconds, microseconds, 1, |
| PyDateTimeAPI->DeltaType); |
| } |
| |
| return rv; |
| } |
| |
| static PyObject * |
| get_date_fromtimestamp(PyObject *self, PyObject *args) |
| { |
| PyObject *tsargs = NULL, *ts = NULL, *rv = NULL; |
| int macro = 0; |
| |
| if (!PyArg_ParseTuple(args, "O|p", &ts, ¯o)) { |
| return NULL; |
| } |
| |
| // Construct the argument tuple |
| if ((tsargs = PyTuple_Pack(1, ts)) == NULL) { |
| return NULL; |
| } |
| |
| // Pass along to the API function |
| if (macro) { |
| rv = PyDate_FromTimestamp(tsargs); |
| } |
| else { |
| rv = PyDateTimeAPI->Date_FromTimestamp( |
| (PyObject *)PyDateTimeAPI->DateType, tsargs |
| ); |
| } |
| |
| Py_DECREF(tsargs); |
| return rv; |
| } |
| |
| static PyObject * |
| get_datetime_fromtimestamp(PyObject *self, PyObject *args) |
| { |
| int macro = 0; |
| int usetz = 0; |
| PyObject *tsargs = NULL, *ts = NULL, *tzinfo = Py_None, *rv = NULL; |
| if (!PyArg_ParseTuple(args, "OO|pp", &ts, &tzinfo, &usetz, ¯o)) { |
| return NULL; |
| } |
| |
| // Construct the argument tuple |
| if (usetz) { |
| tsargs = PyTuple_Pack(2, ts, tzinfo); |
| } |
| else { |
| tsargs = PyTuple_Pack(1, ts); |
| } |
| |
| if (tsargs == NULL) { |
| return NULL; |
| } |
| |
| // Pass along to the API function |
| if (macro) { |
| rv = PyDateTime_FromTimestamp(tsargs); |
| } |
| else { |
| rv = PyDateTimeAPI->DateTime_FromTimestamp( |
| (PyObject *)PyDateTimeAPI->DateTimeType, tsargs, NULL |
| ); |
| } |
| |
| Py_DECREF(tsargs); |
| return rv; |
| } |
| |
| static PyObject * |
| test_PyDateTime_GET(PyObject *self, PyObject *obj) |
| { |
| int year, month, day; |
| |
| year = PyDateTime_GET_YEAR(obj); |
| month = PyDateTime_GET_MONTH(obj); |
| day = PyDateTime_GET_DAY(obj); |
| |
| return Py_BuildValue("(iii)", year, month, day); |
| } |
| |
| static PyObject * |
| test_PyDateTime_DATE_GET(PyObject *self, PyObject *obj) |
| { |
| int hour = PyDateTime_DATE_GET_HOUR(obj); |
| int minute = PyDateTime_DATE_GET_MINUTE(obj); |
| int second = PyDateTime_DATE_GET_SECOND(obj); |
| int microsecond = PyDateTime_DATE_GET_MICROSECOND(obj); |
| PyObject *tzinfo = PyDateTime_DATE_GET_TZINFO(obj); |
| |
| return Py_BuildValue("(iiiiO)", hour, minute, second, microsecond, tzinfo); |
| } |
| |
| static PyObject * |
| test_PyDateTime_TIME_GET(PyObject *self, PyObject *obj) |
| { |
| int hour = PyDateTime_TIME_GET_HOUR(obj); |
| int minute = PyDateTime_TIME_GET_MINUTE(obj); |
| int second = PyDateTime_TIME_GET_SECOND(obj); |
| int microsecond = PyDateTime_TIME_GET_MICROSECOND(obj); |
| PyObject *tzinfo = PyDateTime_TIME_GET_TZINFO(obj); |
| |
| return Py_BuildValue("(iiiiO)", hour, minute, second, microsecond, tzinfo); |
| } |
| |
| static PyObject * |
| test_PyDateTime_DELTA_GET(PyObject *self, PyObject *obj) |
| { |
| int days = PyDateTime_DELTA_GET_DAYS(obj); |
| int seconds = PyDateTime_DELTA_GET_SECONDS(obj); |
| int microseconds = PyDateTime_DELTA_GET_MICROSECONDS(obj); |
| |
| return Py_BuildValue("(iii)", days, seconds, microseconds); |
| } |
| |
| static PyMethodDef test_methods[] = { |
| {"PyDateTime_DATE_GET", test_PyDateTime_DATE_GET, METH_O}, |
| {"PyDateTime_DELTA_GET", test_PyDateTime_DELTA_GET, METH_O}, |
| {"PyDateTime_GET", test_PyDateTime_GET, METH_O}, |
| {"PyDateTime_TIME_GET", test_PyDateTime_TIME_GET, METH_O}, |
| {"datetime_check_date", datetime_check_date, METH_VARARGS}, |
| {"datetime_check_datetime", datetime_check_datetime, METH_VARARGS}, |
| {"datetime_check_delta", datetime_check_delta, METH_VARARGS}, |
| {"datetime_check_time", datetime_check_time, METH_VARARGS}, |
| {"datetime_check_tzinfo", datetime_check_tzinfo, METH_VARARGS}, |
| {"get_date_fromdate", get_date_fromdate, METH_VARARGS}, |
| {"get_date_fromtimestamp", get_date_fromtimestamp, METH_VARARGS}, |
| {"get_datetime_fromdateandtime", get_datetime_fromdateandtime, METH_VARARGS}, |
| {"get_datetime_fromdateandtimeandfold", get_datetime_fromdateandtimeandfold, METH_VARARGS}, |
| {"get_datetime_fromtimestamp", get_datetime_fromtimestamp, METH_VARARGS}, |
| {"get_delta_fromdsu", get_delta_fromdsu, METH_VARARGS}, |
| {"get_time_fromtime", get_time_fromtime, METH_VARARGS}, |
| {"get_time_fromtimeandfold", get_time_fromtimeandfold, METH_VARARGS}, |
| {"get_timezone_utc_capi", get_timezone_utc_capi, METH_VARARGS}, |
| {"get_timezones_offset_zero", get_timezones_offset_zero, METH_NOARGS}, |
| {"make_timezones_capi", make_timezones_capi, METH_NOARGS}, |
| {"test_datetime_capi", test_datetime_capi, METH_NOARGS}, |
| {NULL}, |
| }; |
| |
| int |
| _PyTestCapi_Init_DateTime(PyObject *mod) |
| { |
| if (PyModule_AddFunctions(mod, test_methods) < 0) { |
| return -1; |
| } |
| return 0; |
| } |