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