Skip to main content

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