1 #include "parts.h"
2
3 #include "datetime.h" // PyDateTimeAPI
4
5
6 static int test_run_counter = 0;
7
8 static PyObject *
9 test_datetime_capi(PyObject *self, PyObject *args)
10 {
11 if (PyDateTimeAPI) {
12 if (test_run_counter) {
13 /* Probably regrtest.py -R */
14 Py_RETURN_NONE;
15 }
16 else {
17 PyErr_SetString(PyExc_AssertionError,
18 "PyDateTime_CAPI somehow initialized");
19 return NULL;
20 }
21 }
22 test_run_counter++;
23 PyDateTime_IMPORT;
24
25 if (PyDateTimeAPI) {
26 Py_RETURN_NONE;
27 }
28 return NULL;
29 }
30
31 /* Functions exposing the C API type checking for testing */
32 #define MAKE_DATETIME_CHECK_FUNC(check_method, exact_method) \
33 do { \
34 PyObject *obj; \
35 int exact = 0; \
36 if (!PyArg_ParseTuple(args, "O|p", &obj, &exact)) { \
37 return NULL; \
38 } \
39 int rv = exact?exact_method(obj):check_method(obj); \
40 if (rv) { \
41 Py_RETURN_TRUE; \
42 } \
43 Py_RETURN_FALSE; \
44 } while (0) \
45
46 static PyObject *
47 datetime_check_date(PyObject *self, PyObject *args)
48 {
49 MAKE_DATETIME_CHECK_FUNC(PyDate_Check, PyDate_CheckExact);
50 }
51
52 static PyObject *
53 datetime_check_time(PyObject *self, PyObject *args)
54 {
55 MAKE_DATETIME_CHECK_FUNC(PyTime_Check, PyTime_CheckExact);
56 }
57
58 static PyObject *
59 datetime_check_datetime(PyObject *self, PyObject *args)
60 {
61 MAKE_DATETIME_CHECK_FUNC(PyDateTime_Check, PyDateTime_CheckExact);
62 }
63
64 static PyObject *
65 datetime_check_delta(PyObject *self, PyObject *args)
66 {
67 MAKE_DATETIME_CHECK_FUNC(PyDelta_Check, PyDelta_CheckExact);
68 }
69
70 static PyObject *
71 datetime_check_tzinfo(PyObject *self, PyObject *args)
72 {
73 MAKE_DATETIME_CHECK_FUNC(PyTZInfo_Check, PyTZInfo_CheckExact);
74 }
75 #undef MAKE_DATETIME_CHECK_FUNC
76
77
78 /* Makes three variations on timezone representing UTC-5:
79 1. timezone with offset and name from PyDateTimeAPI
80 2. timezone with offset and name from PyTimeZone_FromOffsetAndName
81 3. timezone with offset (no name) from PyTimeZone_FromOffset
82 */
83 static PyObject *
84 make_timezones_capi(PyObject *self, PyObject *args)
85 {
86 PyObject *offset = PyDelta_FromDSU(0, -18000, 0);
87 PyObject *name = PyUnicode_FromString("EST");
88
89 PyObject *est_zone_capi = PyDateTimeAPI->TimeZone_FromTimeZone(offset, name);
90 PyObject *est_zone_macro = PyTimeZone_FromOffsetAndName(offset, name);
91 PyObject *est_zone_macro_noname = PyTimeZone_FromOffset(offset);
92
93 Py_DecRef(offset);
94 Py_DecRef(name);
95
96 PyObject *rv = PyTuple_New(3);
97 if (rv == NULL) {
98 return NULL;
99 }
100
101 PyTuple_SET_ITEM(rv, 0, est_zone_capi);
102 PyTuple_SET_ITEM(rv, 1, est_zone_macro);
103 PyTuple_SET_ITEM(rv, 2, est_zone_macro_noname);
104
105 return rv;
106 }
107
108 static PyObject *
109 get_timezones_offset_zero(PyObject *self, PyObject *args)
110 {
111 PyObject *offset = PyDelta_FromDSU(0, 0, 0);
112 PyObject *name = PyUnicode_FromString("");
113
114 // These two should return the UTC singleton
115 PyObject *utc_singleton_0 = PyTimeZone_FromOffset(offset);
116 PyObject *utc_singleton_1 = PyTimeZone_FromOffsetAndName(offset, NULL);
117
118 // This one will return +00:00 zone, but not the UTC singleton
119 PyObject *non_utc_zone = PyTimeZone_FromOffsetAndName(offset, name);
120
121 Py_DecRef(offset);
122 Py_DecRef(name);
123
124 PyObject *rv = PyTuple_New(3);
125 PyTuple_SET_ITEM(rv, 0, utc_singleton_0);
126 PyTuple_SET_ITEM(rv, 1, utc_singleton_1);
127 PyTuple_SET_ITEM(rv, 2, non_utc_zone);
128
129 return rv;
130 }
131
132 static PyObject *
133 get_timezone_utc_capi(PyObject *self, PyObject *args)
134 {
135 int macro = 0;
136 if (!PyArg_ParseTuple(args, "|p", ¯o)) {
137 return NULL;
138 }
139 if (macro) {
140 return Py_NewRef(PyDateTime_TimeZone_UTC);
141 }
142 return Py_NewRef(PyDateTimeAPI->TimeZone_UTC);
143 }
144
145 static PyObject *
146 get_date_fromdate(PyObject *self, PyObject *args)
147 {
148 PyObject *rv = NULL;
149 int macro;
150 int year, month, day;
151
152 if (!PyArg_ParseTuple(args, "piii", ¯o, &year, &month, &day)) {
153 return NULL;
154 }
155
156 if (macro) {
157 rv = PyDate_FromDate(year, month, day);
158 }
159 else {
160 rv = PyDateTimeAPI->Date_FromDate(
161 year, month, day,
162 PyDateTimeAPI->DateType);
163 }
164 return rv;
165 }
166
167 static PyObject *
168 get_datetime_fromdateandtime(PyObject *self, PyObject *args)
169 {
170 PyObject *rv = NULL;
171 int macro;
172 int year, month, day;
173 int hour, minute, second, microsecond;
174
175 if (!PyArg_ParseTuple(args, "piiiiiii",
176 ¯o,
177 &year, &month, &day,
178 &hour, &minute, &second, µsecond)) {
179 return NULL;
180 }
181
182 if (macro) {
183 rv = PyDateTime_FromDateAndTime(
184 year, month, day,
185 hour, minute, second, microsecond);
186 }
187 else {
188 rv = PyDateTimeAPI->DateTime_FromDateAndTime(
189 year, month, day,
190 hour, minute, second, microsecond,
191 Py_None,
192 PyDateTimeAPI->DateTimeType);
193 }
194 return rv;
195 }
196
197 static PyObject *
198 get_datetime_fromdateandtimeandfold(PyObject *self, PyObject *args)
199 {
200 PyObject *rv = NULL;
201 int macro;
202 int year, month, day;
203 int hour, minute, second, microsecond, fold;
204
205 if (!PyArg_ParseTuple(args, "piiiiiiii",
206 ¯o,
207 &year, &month, &day,
208 &hour, &minute, &second, µsecond,
209 &fold)) {
210 return NULL;
211 }
212
213 if (macro) {
214 rv = PyDateTime_FromDateAndTimeAndFold(
215 year, month, day,
216 hour, minute, second, microsecond,
217 fold);
218 }
219 else {
220 rv = PyDateTimeAPI->DateTime_FromDateAndTimeAndFold(
221 year, month, day,
222 hour, minute, second, microsecond,
223 Py_None,
224 fold,
225 PyDateTimeAPI->DateTimeType);
226 }
227 return rv;
228 }
229
230 static PyObject *
231 get_time_fromtime(PyObject *self, PyObject *args)
232 {
233 PyObject *rv = NULL;
234 int macro;
235 int hour, minute, second, microsecond;
236
237 if (!PyArg_ParseTuple(args, "piiii",
238 ¯o,
239 &hour, &minute, &second, µsecond))
240 {
241 return NULL;
242 }
243
244 if (macro) {
245 rv = PyTime_FromTime(hour, minute, second, microsecond);
246 }
247 else {
248 rv = PyDateTimeAPI->Time_FromTime(
249 hour, minute, second, microsecond,
250 Py_None,
251 PyDateTimeAPI->TimeType);
252 }
253 return rv;
254 }
255
256 static PyObject *
257 get_time_fromtimeandfold(PyObject *self, PyObject *args)
258 {
259 PyObject *rv = NULL;
260 int macro;
261 int hour, minute, second, microsecond, fold;
262
263 if (!PyArg_ParseTuple(args, "piiiii",
264 ¯o,
265 &hour, &minute, &second, µsecond,
266 &fold)) {
267 return NULL;
268 }
269
270 if (macro) {
271 rv = PyTime_FromTimeAndFold(hour, minute, second, microsecond, fold);
272 }
273 else {
274 rv = PyDateTimeAPI->Time_FromTimeAndFold(
275 hour, minute, second, microsecond,
276 Py_None,
277 fold,
278 PyDateTimeAPI->TimeType);
279 }
280 return rv;
281 }
282
283 static PyObject *
284 get_delta_fromdsu(PyObject *self, PyObject *args)
285 {
286 PyObject *rv = NULL;
287 int macro;
288 int days, seconds, microseconds;
289
290 if (!PyArg_ParseTuple(args, "piii",
291 ¯o,
292 &days, &seconds, µseconds)) {
293 return NULL;
294 }
295
296 if (macro) {
297 rv = PyDelta_FromDSU(days, seconds, microseconds);
298 }
299 else {
300 rv = PyDateTimeAPI->Delta_FromDelta(
301 days, seconds, microseconds, 1,
302 PyDateTimeAPI->DeltaType);
303 }
304
305 return rv;
306 }
307
308 static PyObject *
309 get_date_fromtimestamp(PyObject *self, PyObject *args)
310 {
311 PyObject *tsargs = NULL, *ts = NULL, *rv = NULL;
312 int macro = 0;
313
314 if (!PyArg_ParseTuple(args, "O|p", &ts, ¯o)) {
315 return NULL;
316 }
317
318 // Construct the argument tuple
319 if ((tsargs = PyTuple_Pack(1, ts)) == NULL) {
320 return NULL;
321 }
322
323 // Pass along to the API function
324 if (macro) {
325 rv = PyDate_FromTimestamp(tsargs);
326 }
327 else {
328 rv = PyDateTimeAPI->Date_FromTimestamp(
329 (PyObject *)PyDateTimeAPI->DateType, tsargs
330 );
331 }
332
333 Py_DECREF(tsargs);
334 return rv;
335 }
336
337 static PyObject *
338 get_datetime_fromtimestamp(PyObject *self, PyObject *args)
339 {
340 int macro = 0;
341 int usetz = 0;
342 PyObject *tsargs = NULL, *ts = NULL, *tzinfo = Py_None, *rv = NULL;
343 if (!PyArg_ParseTuple(args, "OO|pp", &ts, &tzinfo, &usetz, ¯o)) {
344 return NULL;
345 }
346
347 // Construct the argument tuple
348 if (usetz) {
349 tsargs = PyTuple_Pack(2, ts, tzinfo);
350 }
351 else {
352 tsargs = PyTuple_Pack(1, ts);
353 }
354
355 if (tsargs == NULL) {
356 return NULL;
357 }
358
359 // Pass along to the API function
360 if (macro) {
361 rv = PyDateTime_FromTimestamp(tsargs);
362 }
363 else {
364 rv = PyDateTimeAPI->DateTime_FromTimestamp(
365 (PyObject *)PyDateTimeAPI->DateTimeType, tsargs, NULL
366 );
367 }
368
369 Py_DECREF(tsargs);
370 return rv;
371 }
372
373 static PyObject *
374 test_PyDateTime_GET(PyObject *self, PyObject *obj)
375 {
376 int year, month, day;
377
378 year = PyDateTime_GET_YEAR(obj);
379 month = PyDateTime_GET_MONTH(obj);
380 day = PyDateTime_GET_DAY(obj);
381
382 return Py_BuildValue("(iii)", year, month, day);
383 }
384
385 static PyObject *
386 test_PyDateTime_DATE_GET(PyObject *self, PyObject *obj)
387 {
388 int hour = PyDateTime_DATE_GET_HOUR(obj);
389 int minute = PyDateTime_DATE_GET_MINUTE(obj);
390 int second = PyDateTime_DATE_GET_SECOND(obj);
391 int microsecond = PyDateTime_DATE_GET_MICROSECOND(obj);
392 PyObject *tzinfo = PyDateTime_DATE_GET_TZINFO(obj);
393
394 return Py_BuildValue("(iiiiO)", hour, minute, second, microsecond, tzinfo);
395 }
396
397 static PyObject *
398 test_PyDateTime_TIME_GET(PyObject *self, PyObject *obj)
399 {
400 int hour = PyDateTime_TIME_GET_HOUR(obj);
401 int minute = PyDateTime_TIME_GET_MINUTE(obj);
402 int second = PyDateTime_TIME_GET_SECOND(obj);
403 int microsecond = PyDateTime_TIME_GET_MICROSECOND(obj);
404 PyObject *tzinfo = PyDateTime_TIME_GET_TZINFO(obj);
405
406 return Py_BuildValue("(iiiiO)", hour, minute, second, microsecond, tzinfo);
407 }
408
409 static PyObject *
410 test_PyDateTime_DELTA_GET(PyObject *self, PyObject *obj)
411 {
412 int days = PyDateTime_DELTA_GET_DAYS(obj);
413 int seconds = PyDateTime_DELTA_GET_SECONDS(obj);
414 int microseconds = PyDateTime_DELTA_GET_MICROSECONDS(obj);
415
416 return Py_BuildValue("(iii)", days, seconds, microseconds);
417 }
418
419 static PyMethodDef test_methods[] = {
420 {"PyDateTime_DATE_GET", test_PyDateTime_DATE_GET, METH_O},
421 {"PyDateTime_DELTA_GET", test_PyDateTime_DELTA_GET, METH_O},
422 {"PyDateTime_GET", test_PyDateTime_GET, METH_O},
423 {"PyDateTime_TIME_GET", test_PyDateTime_TIME_GET, METH_O},
424 {"datetime_check_date", datetime_check_date, METH_VARARGS},
425 {"datetime_check_datetime", datetime_check_datetime, METH_VARARGS},
426 {"datetime_check_delta", datetime_check_delta, METH_VARARGS},
427 {"datetime_check_time", datetime_check_time, METH_VARARGS},
428 {"datetime_check_tzinfo", datetime_check_tzinfo, METH_VARARGS},
429 {"get_date_fromdate", get_date_fromdate, METH_VARARGS},
430 {"get_date_fromtimestamp", get_date_fromtimestamp, METH_VARARGS},
431 {"get_datetime_fromdateandtime", get_datetime_fromdateandtime, METH_VARARGS},
432 {"get_datetime_fromdateandtimeandfold", get_datetime_fromdateandtimeandfold, METH_VARARGS},
433 {"get_datetime_fromtimestamp", get_datetime_fromtimestamp, METH_VARARGS},
434 {"get_delta_fromdsu", get_delta_fromdsu, METH_VARARGS},
435 {"get_time_fromtime", get_time_fromtime, METH_VARARGS},
436 {"get_time_fromtimeandfold", get_time_fromtimeandfold, METH_VARARGS},
437 {"get_timezone_utc_capi", get_timezone_utc_capi, METH_VARARGS},
438 {"get_timezones_offset_zero", get_timezones_offset_zero, METH_NOARGS},
439 {"make_timezones_capi", make_timezones_capi, METH_NOARGS},
440 {"test_datetime_capi", test_datetime_capi, METH_NOARGS},
441 {NULL},
442 };
443
444 int
445 _PyTestCapi_Init_DateTime(PyObject *mod)
446 {
447 if (PyModule_AddFunctions(mod, test_methods) < 0) {
448 return -1;
449 }
450 return 0;
451 }