pyo3_ffi/
datetime.rs

1//! FFI bindings to the functions and structs defined in `datetime.h`
2//!
3//! This is the unsafe thin  wrapper around the [CPython C API](https://docs.python.org/3/c-api/datetime.html),
4//! and covers the various date and time related objects in the Python `datetime`
5//! standard library module.
6//!
7//! A note regarding PyPy (cpyext) support:
8//!
9//! Support for `PyDateTime_CAPI` is limited as of PyPy 7.0.0.
10//! `DateTime_FromTimestamp` and `Date_FromTimestamp` are currently not supported.
11
12#[cfg(GraalPy)]
13use crate::{PyLong_AsLong, PyLong_Check, PyObject_GetAttrString, Py_DecRef};
14use crate::{PyObject, PyObject_TypeCheck, PyTypeObject, Py_TYPE};
15use std::cell::UnsafeCell;
16#[cfg(not(GraalPy))]
17use std::os::raw::c_char;
18use std::os::raw::c_int;
19use std::ptr;
20#[cfg(not(PyPy))]
21use {crate::PyCapsule_Import, std::ffi::CString};
22#[cfg(not(any(PyPy, GraalPy)))]
23use {crate::Py_hash_t, std::os::raw::c_uchar};
24// Type struct wrappers
25const _PyDateTime_DATE_DATASIZE: usize = 4;
26const _PyDateTime_TIME_DATASIZE: usize = 6;
27const _PyDateTime_DATETIME_DATASIZE: usize = 10;
28
29#[repr(C)]
30#[derive(Debug, Copy, Clone)]
31/// Structure representing a `datetime.timedelta`.
32pub struct PyDateTime_Delta {
33    pub ob_base: PyObject,
34    #[cfg(not(any(PyPy, GraalPy)))]
35    pub hashcode: Py_hash_t,
36    #[cfg(not(GraalPy))]
37    pub days: c_int,
38    #[cfg(not(GraalPy))]
39    pub seconds: c_int,
40    #[cfg(not(GraalPy))]
41    pub microseconds: c_int,
42}
43
44// skipped non-limited PyDateTime_TZInfo
45// skipped non-limited _PyDateTime_BaseTZInfo
46
47#[cfg(not(any(PyPy, GraalPy)))]
48#[repr(C)]
49#[derive(Debug, Copy, Clone)]
50/// Structure representing a `datetime.time` without a `tzinfo` member.
51pub struct _PyDateTime_BaseTime {
52    pub ob_base: PyObject,
53    pub hashcode: Py_hash_t,
54    pub hastzinfo: c_char,
55    pub data: [c_uchar; _PyDateTime_TIME_DATASIZE],
56}
57
58#[repr(C)]
59#[derive(Debug, Copy, Clone)]
60/// Structure representing a `datetime.time`.
61pub struct PyDateTime_Time {
62    pub ob_base: PyObject,
63    #[cfg(not(any(PyPy, GraalPy)))]
64    pub hashcode: Py_hash_t,
65    #[cfg(not(GraalPy))]
66    pub hastzinfo: c_char,
67    #[cfg(not(any(PyPy, GraalPy)))]
68    pub data: [c_uchar; _PyDateTime_TIME_DATASIZE],
69    #[cfg(not(any(PyPy, GraalPy)))]
70    pub fold: c_uchar,
71    /// # Safety
72    ///
73    /// Care should be taken when reading this field. If the time does not have a
74    /// tzinfo then CPython may allocate as a `_PyDateTime_BaseTime` without this field.
75    #[cfg(not(GraalPy))]
76    pub tzinfo: *mut PyObject,
77}
78
79#[repr(C)]
80#[derive(Debug, Copy, Clone)]
81/// Structure representing a `datetime.date`
82pub struct PyDateTime_Date {
83    pub ob_base: PyObject,
84    #[cfg(not(any(PyPy, GraalPy)))]
85    pub hashcode: Py_hash_t,
86    #[cfg(not(any(PyPy, GraalPy)))]
87    pub hastzinfo: c_char,
88    #[cfg(not(any(PyPy, GraalPy)))]
89    pub data: [c_uchar; _PyDateTime_DATE_DATASIZE],
90}
91
92#[cfg(not(any(PyPy, GraalPy)))]
93#[repr(C)]
94#[derive(Debug, Copy, Clone)]
95/// Structure representing a `datetime.datetime` without a `tzinfo` member.
96pub struct _PyDateTime_BaseDateTime {
97    pub ob_base: PyObject,
98    pub hashcode: Py_hash_t,
99    pub hastzinfo: c_char,
100    pub data: [c_uchar; _PyDateTime_DATETIME_DATASIZE],
101}
102
103#[repr(C)]
104#[derive(Debug, Copy, Clone)]
105/// Structure representing a `datetime.datetime`.
106pub struct PyDateTime_DateTime {
107    pub ob_base: PyObject,
108    #[cfg(not(any(PyPy, GraalPy)))]
109    pub hashcode: Py_hash_t,
110    #[cfg(not(GraalPy))]
111    pub hastzinfo: c_char,
112    #[cfg(not(any(PyPy, GraalPy)))]
113    pub data: [c_uchar; _PyDateTime_DATETIME_DATASIZE],
114    #[cfg(not(any(PyPy, GraalPy)))]
115    pub fold: c_uchar,
116    /// # Safety
117    ///
118    /// Care should be taken when reading this field. If the time does not have a
119    /// tzinfo then CPython may allocate as a `_PyDateTime_BaseDateTime` without this field.
120    #[cfg(not(GraalPy))]
121    pub tzinfo: *mut PyObject,
122}
123
124// skipped non-limited _PyDateTime_HAS_TZINFO
125
126// Accessor functions for PyDateTime_Date and PyDateTime_DateTime
127#[inline]
128#[cfg(not(any(PyPy, GraalPy)))]
129/// Retrieve the year component of a `PyDateTime_Date` or `PyDateTime_DateTime`.
130/// Returns a signed integer greater than 0.
131pub unsafe fn PyDateTime_GET_YEAR(o: *mut PyObject) -> c_int {
132    // This should work for Date or DateTime
133    let d = *(o as *mut PyDateTime_Date);
134    c_int::from(d.data[0]) << 8 | c_int::from(d.data[1])
135}
136
137#[inline]
138#[cfg(not(any(PyPy, GraalPy)))]
139/// Retrieve the month component of a `PyDateTime_Date` or `PyDateTime_DateTime`.
140/// Returns a signed integer in the range `[1, 12]`.
141pub unsafe fn PyDateTime_GET_MONTH(o: *mut PyObject) -> c_int {
142    let d = *(o as *mut PyDateTime_Date);
143    c_int::from(d.data[2])
144}
145
146#[inline]
147#[cfg(not(any(PyPy, GraalPy)))]
148/// Retrieve the day component of a `PyDateTime_Date` or `PyDateTime_DateTime`.
149/// Returns a signed integer in the interval `[1, 31]`.
150pub unsafe fn PyDateTime_GET_DAY(o: *mut PyObject) -> c_int {
151    let d = *(o as *mut PyDateTime_Date);
152    c_int::from(d.data[3])
153}
154
155// Accessor macros for times
156#[cfg(not(any(PyPy, GraalPy)))]
157macro_rules! _PyDateTime_GET_HOUR {
158    ($o: expr, $offset:expr) => {
159        c_int::from((*$o).data[$offset + 0])
160    };
161}
162
163#[cfg(not(any(PyPy, GraalPy)))]
164macro_rules! _PyDateTime_GET_MINUTE {
165    ($o: expr, $offset:expr) => {
166        c_int::from((*$o).data[$offset + 1])
167    };
168}
169
170#[cfg(not(any(PyPy, GraalPy)))]
171macro_rules! _PyDateTime_GET_SECOND {
172    ($o: expr, $offset:expr) => {
173        c_int::from((*$o).data[$offset + 2])
174    };
175}
176
177#[cfg(not(any(PyPy, GraalPy)))]
178macro_rules! _PyDateTime_GET_MICROSECOND {
179    ($o: expr, $offset:expr) => {
180        (c_int::from((*$o).data[$offset + 3]) << 16)
181            | (c_int::from((*$o).data[$offset + 4]) << 8)
182            | (c_int::from((*$o).data[$offset + 5]))
183    };
184}
185
186#[cfg(not(any(PyPy, GraalPy)))]
187macro_rules! _PyDateTime_GET_FOLD {
188    ($o: expr) => {
189        (*$o).fold
190    };
191}
192
193#[cfg(not(any(PyPy, GraalPy)))]
194macro_rules! _PyDateTime_GET_TZINFO {
195    ($o: expr) => {
196        if (*$o).hastzinfo != 0 {
197            (*$o).tzinfo
198        } else {
199            $crate::Py_None()
200        }
201    };
202}
203
204// Accessor functions for DateTime
205#[inline]
206#[cfg(not(any(PyPy, GraalPy)))]
207/// Retrieve the hour component of a `PyDateTime_DateTime`.
208/// Returns a signed integer in the interval `[0, 23]`
209pub unsafe fn PyDateTime_DATE_GET_HOUR(o: *mut PyObject) -> c_int {
210    _PyDateTime_GET_HOUR!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
211}
212
213#[inline]
214#[cfg(not(any(PyPy, GraalPy)))]
215/// Retrieve the minute component of a `PyDateTime_DateTime`.
216/// Returns a signed integer in the interval `[0, 59]`
217pub unsafe fn PyDateTime_DATE_GET_MINUTE(o: *mut PyObject) -> c_int {
218    _PyDateTime_GET_MINUTE!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
219}
220
221#[inline]
222#[cfg(not(any(PyPy, GraalPy)))]
223/// Retrieve the second component of a `PyDateTime_DateTime`.
224/// Returns a signed integer in the interval `[0, 59]`
225pub unsafe fn PyDateTime_DATE_GET_SECOND(o: *mut PyObject) -> c_int {
226    _PyDateTime_GET_SECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
227}
228
229#[inline]
230#[cfg(not(any(PyPy, GraalPy)))]
231/// Retrieve the microsecond component of a `PyDateTime_DateTime`.
232/// Returns a signed integer in the interval `[0, 999999]`
233pub unsafe fn PyDateTime_DATE_GET_MICROSECOND(o: *mut PyObject) -> c_int {
234    _PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
235}
236
237#[inline]
238#[cfg(not(any(PyPy, GraalPy)))]
239/// Retrieve the fold component of a `PyDateTime_DateTime`.
240/// Returns a signed integer in the interval `[0, 1]`
241pub unsafe fn PyDateTime_DATE_GET_FOLD(o: *mut PyObject) -> c_uchar {
242    _PyDateTime_GET_FOLD!(o as *mut PyDateTime_DateTime)
243}
244
245#[inline]
246#[cfg(not(any(PyPy, GraalPy)))]
247/// Retrieve the tzinfo component of a `PyDateTime_DateTime`.
248/// Returns a pointer to a `PyObject` that should be either NULL or an instance
249/// of a `datetime.tzinfo` subclass.
250pub unsafe fn PyDateTime_DATE_GET_TZINFO(o: *mut PyObject) -> *mut PyObject {
251    _PyDateTime_GET_TZINFO!(o as *mut PyDateTime_DateTime)
252}
253
254// Accessor functions for Time
255#[inline]
256#[cfg(not(any(PyPy, GraalPy)))]
257/// Retrieve the hour component of a `PyDateTime_Time`.
258/// Returns a signed integer in the interval `[0, 23]`
259pub unsafe fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int {
260    _PyDateTime_GET_HOUR!((o as *mut PyDateTime_Time), 0)
261}
262
263#[inline]
264#[cfg(not(any(PyPy, GraalPy)))]
265/// Retrieve the minute component of a `PyDateTime_Time`.
266/// Returns a signed integer in the interval `[0, 59]`
267pub unsafe fn PyDateTime_TIME_GET_MINUTE(o: *mut PyObject) -> c_int {
268    _PyDateTime_GET_MINUTE!((o as *mut PyDateTime_Time), 0)
269}
270
271#[inline]
272#[cfg(not(any(PyPy, GraalPy)))]
273/// Retrieve the second component of a `PyDateTime_DateTime`.
274/// Returns a signed integer in the interval `[0, 59]`
275pub unsafe fn PyDateTime_TIME_GET_SECOND(o: *mut PyObject) -> c_int {
276    _PyDateTime_GET_SECOND!((o as *mut PyDateTime_Time), 0)
277}
278
279#[inline]
280#[cfg(not(any(PyPy, GraalPy)))]
281/// Retrieve the microsecond component of a `PyDateTime_DateTime`.
282/// Returns a signed integer in the interval `[0, 999999]`
283pub unsafe fn PyDateTime_TIME_GET_MICROSECOND(o: *mut PyObject) -> c_int {
284    _PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_Time), 0)
285}
286
287#[cfg(not(any(PyPy, GraalPy)))]
288#[inline]
289/// Retrieve the fold component of a `PyDateTime_Time`.
290/// Returns a signed integer in the interval `[0, 1]`
291pub unsafe fn PyDateTime_TIME_GET_FOLD(o: *mut PyObject) -> c_uchar {
292    _PyDateTime_GET_FOLD!(o as *mut PyDateTime_Time)
293}
294
295#[inline]
296#[cfg(not(any(PyPy, GraalPy)))]
297/// Retrieve the tzinfo component of a `PyDateTime_Time`.
298/// Returns a pointer to a `PyObject` that should be either NULL or an instance
299/// of a `datetime.tzinfo` subclass.
300pub unsafe fn PyDateTime_TIME_GET_TZINFO(o: *mut PyObject) -> *mut PyObject {
301    _PyDateTime_GET_TZINFO!(o as *mut PyDateTime_Time)
302}
303
304// Accessor functions
305#[cfg(not(any(PyPy, GraalPy)))]
306macro_rules! _access_field {
307    ($obj:expr, $type: ident, $field:ident) => {
308        (*($obj as *mut $type)).$field
309    };
310}
311
312// Accessor functions for PyDateTime_Delta
313#[cfg(not(any(PyPy, GraalPy)))]
314macro_rules! _access_delta_field {
315    ($obj:expr, $field:ident) => {
316        _access_field!($obj, PyDateTime_Delta, $field)
317    };
318}
319
320#[inline]
321#[cfg(not(any(PyPy, GraalPy)))]
322/// Retrieve the days component of a `PyDateTime_Delta`.
323///
324/// Returns a signed integer in the interval [-999999999, 999999999].
325///
326/// Note: This retrieves a component from the underlying structure, it is *not*
327/// a representation of the total duration of the structure.
328pub unsafe fn PyDateTime_DELTA_GET_DAYS(o: *mut PyObject) -> c_int {
329    _access_delta_field!(o, days)
330}
331
332#[inline]
333#[cfg(not(any(PyPy, GraalPy)))]
334/// Retrieve the seconds component of a `PyDateTime_Delta`.
335///
336/// Returns a signed integer in the interval [0, 86399].
337///
338/// Note: This retrieves a component from the underlying structure, it is *not*
339/// a representation of the total duration of the structure.
340pub unsafe fn PyDateTime_DELTA_GET_SECONDS(o: *mut PyObject) -> c_int {
341    _access_delta_field!(o, seconds)
342}
343
344#[inline]
345#[cfg(not(any(PyPy, GraalPy)))]
346/// Retrieve the seconds component of a `PyDateTime_Delta`.
347///
348/// Returns a signed integer in the interval [0, 999999].
349///
350/// Note: This retrieves a component from the underlying structure, it is *not*
351/// a representation of the total duration of the structure.
352pub unsafe fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int {
353    _access_delta_field!(o, microseconds)
354}
355
356// Accessor functions for GraalPy. The macros on GraalPy work differently,
357// but copying them seems suboptimal
358#[inline]
359#[cfg(GraalPy)]
360pub unsafe fn _get_attr(obj: *mut PyObject, field: &std::ffi::CStr) -> c_int {
361    let result = PyObject_GetAttrString(obj, field.as_ptr());
362    Py_DecRef(result); // the original macros are borrowing
363    if PyLong_Check(result) == 1 {
364        PyLong_AsLong(result) as c_int
365    } else {
366        0
367    }
368}
369
370#[inline]
371#[cfg(GraalPy)]
372pub unsafe fn PyDateTime_GET_YEAR(o: *mut PyObject) -> c_int {
373    _get_attr(o, c_str!("year"))
374}
375
376#[inline]
377#[cfg(GraalPy)]
378pub unsafe fn PyDateTime_GET_MONTH(o: *mut PyObject) -> c_int {
379    _get_attr(o, c_str!("month"))
380}
381
382#[inline]
383#[cfg(GraalPy)]
384pub unsafe fn PyDateTime_GET_DAY(o: *mut PyObject) -> c_int {
385    _get_attr(o, c_str!("day"))
386}
387
388#[inline]
389#[cfg(GraalPy)]
390pub unsafe fn PyDateTime_DATE_GET_HOUR(o: *mut PyObject) -> c_int {
391    _get_attr(o, c_str!("hour"))
392}
393
394#[inline]
395#[cfg(GraalPy)]
396pub unsafe fn PyDateTime_DATE_GET_MINUTE(o: *mut PyObject) -> c_int {
397    _get_attr(o, c_str!("minute"))
398}
399
400#[inline]
401#[cfg(GraalPy)]
402pub unsafe fn PyDateTime_DATE_GET_SECOND(o: *mut PyObject) -> c_int {
403    _get_attr(o, c_str!("second"))
404}
405
406#[inline]
407#[cfg(GraalPy)]
408pub unsafe fn PyDateTime_DATE_GET_MICROSECOND(o: *mut PyObject) -> c_int {
409    _get_attr(o, c_str!("microsecond"))
410}
411
412#[inline]
413#[cfg(GraalPy)]
414pub unsafe fn PyDateTime_DATE_GET_FOLD(o: *mut PyObject) -> c_int {
415    _get_attr(o, c_str!("fold"))
416}
417
418#[inline]
419#[cfg(GraalPy)]
420pub unsafe fn PyDateTime_DATE_GET_TZINFO(o: *mut PyObject) -> *mut PyObject {
421    let res = PyObject_GetAttrString(o, c_str!("tzinfo").as_ptr().cast());
422    Py_DecRef(res); // the original macros are borrowing
423    res
424}
425
426#[inline]
427#[cfg(GraalPy)]
428pub unsafe fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int {
429    _get_attr(o, c_str!("hour"))
430}
431
432#[inline]
433#[cfg(GraalPy)]
434pub unsafe fn PyDateTime_TIME_GET_MINUTE(o: *mut PyObject) -> c_int {
435    _get_attr(o, c_str!("minute"))
436}
437
438#[inline]
439#[cfg(GraalPy)]
440pub unsafe fn PyDateTime_TIME_GET_SECOND(o: *mut PyObject) -> c_int {
441    _get_attr(o, c_str!("second"))
442}
443
444#[inline]
445#[cfg(GraalPy)]
446pub unsafe fn PyDateTime_TIME_GET_MICROSECOND(o: *mut PyObject) -> c_int {
447    _get_attr(o, c_str!("microsecond"))
448}
449
450#[inline]
451#[cfg(GraalPy)]
452pub unsafe fn PyDateTime_TIME_GET_FOLD(o: *mut PyObject) -> c_int {
453    _get_attr(o, c_str!("fold"))
454}
455
456#[inline]
457#[cfg(GraalPy)]
458pub unsafe fn PyDateTime_TIME_GET_TZINFO(o: *mut PyObject) -> *mut PyObject {
459    let res = PyObject_GetAttrString(o, c_str!("tzinfo").as_ptr().cast());
460    Py_DecRef(res); // the original macros are borrowing
461    res
462}
463
464#[inline]
465#[cfg(GraalPy)]
466pub unsafe fn PyDateTime_DELTA_GET_DAYS(o: *mut PyObject) -> c_int {
467    _get_attr(o, c_str!("days"))
468}
469
470#[inline]
471#[cfg(GraalPy)]
472pub unsafe fn PyDateTime_DELTA_GET_SECONDS(o: *mut PyObject) -> c_int {
473    _get_attr(o, c_str!("seconds"))
474}
475
476#[inline]
477#[cfg(GraalPy)]
478pub unsafe fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int {
479    _get_attr(o, c_str!("microseconds"))
480}
481
482#[cfg(PyPy)]
483extern "C" {
484    // skipped _PyDateTime_HAS_TZINFO (not in PyPy)
485    #[link_name = "PyPyDateTime_GET_YEAR"]
486    pub fn PyDateTime_GET_YEAR(o: *mut PyObject) -> c_int;
487    #[link_name = "PyPyDateTime_GET_MONTH"]
488    pub fn PyDateTime_GET_MONTH(o: *mut PyObject) -> c_int;
489    #[link_name = "PyPyDateTime_GET_DAY"]
490    pub fn PyDateTime_GET_DAY(o: *mut PyObject) -> c_int;
491
492    #[link_name = "PyPyDateTime_DATE_GET_HOUR"]
493    pub fn PyDateTime_DATE_GET_HOUR(o: *mut PyObject) -> c_int;
494    #[link_name = "PyPyDateTime_DATE_GET_MINUTE"]
495    pub fn PyDateTime_DATE_GET_MINUTE(o: *mut PyObject) -> c_int;
496    #[link_name = "PyPyDateTime_DATE_GET_SECOND"]
497    pub fn PyDateTime_DATE_GET_SECOND(o: *mut PyObject) -> c_int;
498    #[link_name = "PyPyDateTime_DATE_GET_MICROSECOND"]
499    pub fn PyDateTime_DATE_GET_MICROSECOND(o: *mut PyObject) -> c_int;
500    #[link_name = "PyPyDateTime_GET_FOLD"]
501    pub fn PyDateTime_DATE_GET_FOLD(o: *mut PyObject) -> c_int;
502    // skipped PyDateTime_DATE_GET_TZINFO (not in PyPy)
503
504    #[link_name = "PyPyDateTime_TIME_GET_HOUR"]
505    pub fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int;
506    #[link_name = "PyPyDateTime_TIME_GET_MINUTE"]
507    pub fn PyDateTime_TIME_GET_MINUTE(o: *mut PyObject) -> c_int;
508    #[link_name = "PyPyDateTime_TIME_GET_SECOND"]
509    pub fn PyDateTime_TIME_GET_SECOND(o: *mut PyObject) -> c_int;
510    #[link_name = "PyPyDateTime_TIME_GET_MICROSECOND"]
511    pub fn PyDateTime_TIME_GET_MICROSECOND(o: *mut PyObject) -> c_int;
512    #[link_name = "PyPyDateTime_TIME_GET_FOLD"]
513    pub fn PyDateTime_TIME_GET_FOLD(o: *mut PyObject) -> c_int;
514    // skipped PyDateTime_TIME_GET_TZINFO (not in PyPy)
515
516    #[link_name = "PyPyDateTime_DELTA_GET_DAYS"]
517    pub fn PyDateTime_DELTA_GET_DAYS(o: *mut PyObject) -> c_int;
518    #[link_name = "PyPyDateTime_DELTA_GET_SECONDS"]
519    pub fn PyDateTime_DELTA_GET_SECONDS(o: *mut PyObject) -> c_int;
520    #[link_name = "PyPyDateTime_DELTA_GET_MICROSECONDS"]
521    pub fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int;
522}
523
524#[repr(C)]
525#[derive(Debug, Copy, Clone)]
526pub struct PyDateTime_CAPI {
527    pub DateType: *mut PyTypeObject,
528    pub DateTimeType: *mut PyTypeObject,
529    pub TimeType: *mut PyTypeObject,
530    pub DeltaType: *mut PyTypeObject,
531    pub TZInfoType: *mut PyTypeObject,
532    pub TimeZone_UTC: *mut PyObject,
533    pub Date_FromDate: unsafe extern "C" fn(
534        year: c_int,
535        month: c_int,
536        day: c_int,
537        cls: *mut PyTypeObject,
538    ) -> *mut PyObject,
539    pub DateTime_FromDateAndTime: unsafe extern "C" fn(
540        year: c_int,
541        month: c_int,
542        day: c_int,
543        hour: c_int,
544        minute: c_int,
545        second: c_int,
546        microsecond: c_int,
547        tzinfo: *mut PyObject,
548        cls: *mut PyTypeObject,
549    ) -> *mut PyObject,
550    pub Time_FromTime: unsafe extern "C" fn(
551        hour: c_int,
552        minute: c_int,
553        second: c_int,
554        microsecond: c_int,
555        tzinfo: *mut PyObject,
556        cls: *mut PyTypeObject,
557    ) -> *mut PyObject,
558    pub Delta_FromDelta: unsafe extern "C" fn(
559        days: c_int,
560        seconds: c_int,
561        microseconds: c_int,
562        normalize: c_int,
563        cls: *mut PyTypeObject,
564    ) -> *mut PyObject,
565    pub TimeZone_FromTimeZone:
566        unsafe extern "C" fn(offset: *mut PyObject, name: *mut PyObject) -> *mut PyObject,
567
568    pub DateTime_FromTimestamp: unsafe extern "C" fn(
569        cls: *mut PyTypeObject,
570        args: *mut PyObject,
571        kwargs: *mut PyObject,
572    ) -> *mut PyObject,
573    pub Date_FromTimestamp:
574        unsafe extern "C" fn(cls: *mut PyTypeObject, args: *mut PyObject) -> *mut PyObject,
575    pub DateTime_FromDateAndTimeAndFold: unsafe extern "C" fn(
576        year: c_int,
577        month: c_int,
578        day: c_int,
579        hour: c_int,
580        minute: c_int,
581        second: c_int,
582        microsecond: c_int,
583        tzinfo: *mut PyObject,
584        fold: c_int,
585        cls: *mut PyTypeObject,
586    ) -> *mut PyObject,
587    pub Time_FromTimeAndFold: unsafe extern "C" fn(
588        hour: c_int,
589        minute: c_int,
590        second: c_int,
591        microsecond: c_int,
592        tzinfo: *mut PyObject,
593        fold: c_int,
594        cls: *mut PyTypeObject,
595    ) -> *mut PyObject,
596}
597
598// Python already shares this object between threads, so it's no more evil for us to do it too!
599unsafe impl Sync for PyDateTime_CAPI {}
600
601/// Returns a pointer to a `PyDateTime_CAPI` instance
602///
603/// # Note
604/// This function will return a null pointer until
605/// `PyDateTime_IMPORT` is called
606#[inline]
607pub unsafe fn PyDateTimeAPI() -> *mut PyDateTime_CAPI {
608    *PyDateTimeAPI_impl.0.get()
609}
610
611#[inline]
612pub unsafe fn PyDateTime_TimeZone_UTC() -> *mut PyObject {
613    (*PyDateTimeAPI()).TimeZone_UTC
614}
615
616/// Populates the `PyDateTimeAPI` object
617pub unsafe fn PyDateTime_IMPORT() {
618    // PyPy expects the C-API to be initialized via PyDateTime_Import, so trying to use
619    // `PyCapsule_Import` will behave unexpectedly in pypy.
620    #[cfg(PyPy)]
621    let py_datetime_c_api = PyDateTime_Import();
622
623    #[cfg(not(PyPy))]
624    let py_datetime_c_api = {
625        // PyDateTime_CAPSULE_NAME is a macro in C
626        let PyDateTime_CAPSULE_NAME = CString::new("datetime.datetime_CAPI").unwrap();
627
628        PyCapsule_Import(PyDateTime_CAPSULE_NAME.as_ptr(), 1) as *mut PyDateTime_CAPI
629    };
630
631    *PyDateTimeAPI_impl.0.get() = py_datetime_c_api;
632}
633
634// skipped non-limited PyDateTime_TimeZone_UTC
635
636/// Type Check macros
637///
638/// These are bindings around the C API typecheck macros, all of them return
639/// `1` if True and `0` if False. In all type check macros, the argument (`op`)
640/// must not be `NULL`.
641#[inline]
642/// Check if `op` is a `PyDateTimeAPI.DateType` or subtype.
643pub unsafe fn PyDate_Check(op: *mut PyObject) -> c_int {
644    PyObject_TypeCheck(op, (*PyDateTimeAPI()).DateType) as c_int
645}
646
647#[inline]
648/// Check if `op`'s type is exactly `PyDateTimeAPI.DateType`.
649pub unsafe fn PyDate_CheckExact(op: *mut PyObject) -> c_int {
650    (Py_TYPE(op) == (*PyDateTimeAPI()).DateType) as c_int
651}
652
653#[inline]
654/// Check if `op` is a `PyDateTimeAPI.DateTimeType` or subtype.
655pub unsafe fn PyDateTime_Check(op: *mut PyObject) -> c_int {
656    PyObject_TypeCheck(op, (*PyDateTimeAPI()).DateTimeType) as c_int
657}
658
659#[inline]
660/// Check if `op`'s type is exactly `PyDateTimeAPI.DateTimeType`.
661pub unsafe fn PyDateTime_CheckExact(op: *mut PyObject) -> c_int {
662    (Py_TYPE(op) == (*PyDateTimeAPI()).DateTimeType) as c_int
663}
664
665#[inline]
666/// Check if `op` is a `PyDateTimeAPI.TimeType` or subtype.
667pub unsafe fn PyTime_Check(op: *mut PyObject) -> c_int {
668    PyObject_TypeCheck(op, (*PyDateTimeAPI()).TimeType) as c_int
669}
670
671#[inline]
672/// Check if `op`'s type is exactly `PyDateTimeAPI.TimeType`.
673pub unsafe fn PyTime_CheckExact(op: *mut PyObject) -> c_int {
674    (Py_TYPE(op) == (*PyDateTimeAPI()).TimeType) as c_int
675}
676
677#[inline]
678/// Check if `op` is a `PyDateTimeAPI.DetaType` or subtype.
679pub unsafe fn PyDelta_Check(op: *mut PyObject) -> c_int {
680    PyObject_TypeCheck(op, (*PyDateTimeAPI()).DeltaType) as c_int
681}
682
683#[inline]
684/// Check if `op`'s type is exactly `PyDateTimeAPI.DeltaType`.
685pub unsafe fn PyDelta_CheckExact(op: *mut PyObject) -> c_int {
686    (Py_TYPE(op) == (*PyDateTimeAPI()).DeltaType) as c_int
687}
688
689#[inline]
690/// Check if `op` is a `PyDateTimeAPI.TZInfoType` or subtype.
691pub unsafe fn PyTZInfo_Check(op: *mut PyObject) -> c_int {
692    PyObject_TypeCheck(op, (*PyDateTimeAPI()).TZInfoType) as c_int
693}
694
695#[inline]
696/// Check if `op`'s type is exactly `PyDateTimeAPI.TZInfoType`.
697pub unsafe fn PyTZInfo_CheckExact(op: *mut PyObject) -> c_int {
698    (Py_TYPE(op) == (*PyDateTimeAPI()).TZInfoType) as c_int
699}
700
701// skipped non-limited PyDate_FromDate
702// skipped non-limited PyDateTime_FromDateAndTime
703// skipped non-limited PyDateTime_FromDateAndTimeAndFold
704// skipped non-limited PyTime_FromTime
705// skipped non-limited PyTime_FromTimeAndFold
706// skipped non-limited PyDelta_FromDSU
707
708pub unsafe fn PyTimeZone_FromOffset(offset: *mut PyObject) -> *mut PyObject {
709    ((*PyDateTimeAPI()).TimeZone_FromTimeZone)(offset, std::ptr::null_mut())
710}
711
712pub unsafe fn PyTimeZone_FromOffsetAndName(
713    offset: *mut PyObject,
714    name: *mut PyObject,
715) -> *mut PyObject {
716    ((*PyDateTimeAPI()).TimeZone_FromTimeZone)(offset, name)
717}
718
719#[cfg(not(PyPy))]
720pub unsafe fn PyDateTime_FromTimestamp(args: *mut PyObject) -> *mut PyObject {
721    let f = (*PyDateTimeAPI()).DateTime_FromTimestamp;
722    f((*PyDateTimeAPI()).DateTimeType, args, std::ptr::null_mut())
723}
724
725#[cfg(not(PyPy))]
726pub unsafe fn PyDate_FromTimestamp(args: *mut PyObject) -> *mut PyObject {
727    let f = (*PyDateTimeAPI()).Date_FromTimestamp;
728    f((*PyDateTimeAPI()).DateType, args)
729}
730
731#[cfg(PyPy)]
732extern "C" {
733    #[link_name = "PyPyDate_FromTimestamp"]
734    pub fn PyDate_FromTimestamp(args: *mut PyObject) -> *mut PyObject;
735    #[link_name = "PyPyDateTime_FromTimestamp"]
736    pub fn PyDateTime_FromTimestamp(args: *mut PyObject) -> *mut PyObject;
737}
738
739#[cfg(PyPy)]
740extern "C" {
741    #[link_name = "_PyPyDateTime_Import"]
742    pub fn PyDateTime_Import() -> *mut PyDateTime_CAPI;
743}
744
745// Rust specific implementation details
746
747struct PyDateTimeAPISingleton(UnsafeCell<*mut PyDateTime_CAPI>);
748unsafe impl Sync for PyDateTimeAPISingleton {}
749
750static PyDateTimeAPI_impl: PyDateTimeAPISingleton =
751    PyDateTimeAPISingleton(UnsafeCell::new(ptr::null_mut()));