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    #[link_name = "PyPyDateTime_DATE_GET_TZINFO"]
491    #[cfg(Py_3_10)]
492    pub fn PyDateTime_DATE_GET_TZINFO(o: *mut PyObject) -> *mut PyObject;
493
494    #[link_name = "PyPyDateTime_TIME_GET_HOUR"]
495    pub fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int;
496    #[link_name = "PyPyDateTime_TIME_GET_MINUTE"]
497    pub fn PyDateTime_TIME_GET_MINUTE(o: *mut PyObject) -> c_int;
498    #[link_name = "PyPyDateTime_TIME_GET_SECOND"]
499    pub fn PyDateTime_TIME_GET_SECOND(o: *mut PyObject) -> c_int;
500    #[link_name = "PyPyDateTime_TIME_GET_MICROSECOND"]
501    pub fn PyDateTime_TIME_GET_MICROSECOND(o: *mut PyObject) -> c_int;
502    #[link_name = "PyPyDateTime_TIME_GET_FOLD"]
503    pub fn PyDateTime_TIME_GET_FOLD(o: *mut PyObject) -> c_int;
504    #[link_name = "PyPyDateTime_TIME_GET_TZINFO"]
505    #[cfg(Py_3_10)]
506    pub fn PyDateTime_TIME_GET_TZINFO(o: *mut PyObject) -> *mut PyObject;
507
508    #[link_name = "PyPyDateTime_DELTA_GET_DAYS"]
509    pub fn PyDateTime_DELTA_GET_DAYS(o: *mut PyObject) -> c_int;
510    #[link_name = "PyPyDateTime_DELTA_GET_SECONDS"]
511    pub fn PyDateTime_DELTA_GET_SECONDS(o: *mut PyObject) -> c_int;
512    #[link_name = "PyPyDateTime_DELTA_GET_MICROSECONDS"]
513    pub fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int;
514}
515
516#[repr(C)]
517#[derive(Debug, Copy, Clone)]
518pub struct PyDateTime_CAPI {
519    pub DateType: *mut PyTypeObject,
520    pub DateTimeType: *mut PyTypeObject,
521    pub TimeType: *mut PyTypeObject,
522    pub DeltaType: *mut PyTypeObject,
523    pub TZInfoType: *mut PyTypeObject,
524    pub TimeZone_UTC: *mut PyObject,
525    pub Date_FromDate: unsafe extern "C" fn(
526        year: c_int,
527        month: c_int,
528        day: c_int,
529        cls: *mut PyTypeObject,
530    ) -> *mut PyObject,
531    pub DateTime_FromDateAndTime: unsafe extern "C" fn(
532        year: c_int,
533        month: c_int,
534        day: c_int,
535        hour: c_int,
536        minute: c_int,
537        second: c_int,
538        microsecond: c_int,
539        tzinfo: *mut PyObject,
540        cls: *mut PyTypeObject,
541    ) -> *mut PyObject,
542    pub Time_FromTime: unsafe extern "C" fn(
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 Delta_FromDelta: unsafe extern "C" fn(
551        days: c_int,
552        seconds: c_int,
553        microseconds: c_int,
554        normalize: c_int,
555        cls: *mut PyTypeObject,
556    ) -> *mut PyObject,
557    pub TimeZone_FromTimeZone:
558        unsafe extern "C" fn(offset: *mut PyObject, name: *mut PyObject) -> *mut PyObject,
559
560    pub DateTime_FromTimestamp: unsafe extern "C" fn(
561        cls: *mut PyTypeObject,
562        args: *mut PyObject,
563        kwargs: *mut PyObject,
564    ) -> *mut PyObject,
565    pub Date_FromTimestamp:
566        unsafe extern "C" fn(cls: *mut PyTypeObject, args: *mut PyObject) -> *mut PyObject,
567    pub DateTime_FromDateAndTimeAndFold: unsafe extern "C" fn(
568        year: c_int,
569        month: c_int,
570        day: c_int,
571        hour: c_int,
572        minute: c_int,
573        second: c_int,
574        microsecond: c_int,
575        tzinfo: *mut PyObject,
576        fold: c_int,
577        cls: *mut PyTypeObject,
578    ) -> *mut PyObject,
579    pub Time_FromTimeAndFold: unsafe extern "C" fn(
580        hour: c_int,
581        minute: c_int,
582        second: c_int,
583        microsecond: c_int,
584        tzinfo: *mut PyObject,
585        fold: c_int,
586        cls: *mut PyTypeObject,
587    ) -> *mut PyObject,
588}
589
590// Python already shares this object between threads, so it's no more evil for us to do it too!
591unsafe impl Sync for PyDateTime_CAPI {}
592
593pub const PyDateTime_CAPSULE_NAME: &CStr = c_str!("datetime.datetime_CAPI");
594
595/// Returns a pointer to a `PyDateTime_CAPI` instance
596///
597/// # Note
598/// This function will return a null pointer until
599/// `PyDateTime_IMPORT` is called
600#[inline]
601pub unsafe fn PyDateTimeAPI() -> *mut PyDateTime_CAPI {
602    *PyDateTimeAPI_impl.ptr.get()
603}
604
605/// Populates the `PyDateTimeAPI` object
606pub unsafe fn PyDateTime_IMPORT() {
607    if !PyDateTimeAPI_impl.once.is_completed() {
608        // PyPy expects the C-API to be initialized via PyDateTime_Import, so trying to use
609        // `PyCapsule_Import` will behave unexpectedly in pypy.
610        #[cfg(PyPy)]
611        let py_datetime_c_api = PyDateTime_Import();
612
613        #[cfg(not(PyPy))]
614        let py_datetime_c_api =
615            PyCapsule_Import(PyDateTime_CAPSULE_NAME.as_ptr(), 1) as *mut PyDateTime_CAPI;
616
617        if py_datetime_c_api.is_null() {
618            return;
619        }
620
621        // Protect against race conditions when the datetime API is concurrently
622        // initialized in multiple threads. UnsafeCell.get() cannot panic so this
623        // won't panic either.
624        PyDateTimeAPI_impl.once.call_once(|| {
625            *PyDateTimeAPI_impl.ptr.get() = py_datetime_c_api;
626        });
627    }
628}
629
630#[inline]
631pub unsafe fn PyDateTime_TimeZone_UTC() -> *mut PyObject {
632    (*PyDateTimeAPI()).TimeZone_UTC
633}
634
635/// Type Check macros
636///
637/// These are bindings around the C API typecheck macros, all of them return
638/// `1` if True and `0` if False. In all type check macros, the argument (`op`)
639/// must not be `NULL`.
640#[inline]
641/// Check if `op` is a `PyDateTimeAPI.DateType` or subtype.
642pub unsafe fn PyDate_Check(op: *mut PyObject) -> c_int {
643    PyObject_TypeCheck(op, (*PyDateTimeAPI()).DateType) as c_int
644}
645
646#[inline]
647/// Check if `op`'s type is exactly `PyDateTimeAPI.DateType`.
648pub unsafe fn PyDate_CheckExact(op: *mut PyObject) -> c_int {
649    (Py_TYPE(op) == (*PyDateTimeAPI()).DateType) as c_int
650}
651
652#[inline]
653/// Check if `op` is a `PyDateTimeAPI.DateTimeType` or subtype.
654pub unsafe fn PyDateTime_Check(op: *mut PyObject) -> c_int {
655    PyObject_TypeCheck(op, (*PyDateTimeAPI()).DateTimeType) as c_int
656}
657
658#[inline]
659/// Check if `op`'s type is exactly `PyDateTimeAPI.DateTimeType`.
660pub unsafe fn PyDateTime_CheckExact(op: *mut PyObject) -> c_int {
661    (Py_TYPE(op) == (*PyDateTimeAPI()).DateTimeType) as c_int
662}
663
664#[inline]
665/// Check if `op` is a `PyDateTimeAPI.TimeType` or subtype.
666pub unsafe fn PyTime_Check(op: *mut PyObject) -> c_int {
667    PyObject_TypeCheck(op, (*PyDateTimeAPI()).TimeType) as c_int
668}
669
670#[inline]
671/// Check if `op`'s type is exactly `PyDateTimeAPI.TimeType`.
672pub unsafe fn PyTime_CheckExact(op: *mut PyObject) -> c_int {
673    (Py_TYPE(op) == (*PyDateTimeAPI()).TimeType) as c_int
674}
675
676#[inline]
677/// Check if `op` is a `PyDateTimeAPI.DetaType` or subtype.
678pub unsafe fn PyDelta_Check(op: *mut PyObject) -> c_int {
679    PyObject_TypeCheck(op, (*PyDateTimeAPI()).DeltaType) as c_int
680}
681
682#[inline]
683/// Check if `op`'s type is exactly `PyDateTimeAPI.DeltaType`.
684pub unsafe fn PyDelta_CheckExact(op: *mut PyObject) -> c_int {
685    (Py_TYPE(op) == (*PyDateTimeAPI()).DeltaType) as c_int
686}
687
688#[inline]
689/// Check if `op` is a `PyDateTimeAPI.TZInfoType` or subtype.
690pub unsafe fn PyTZInfo_Check(op: *mut PyObject) -> c_int {
691    PyObject_TypeCheck(op, (*PyDateTimeAPI()).TZInfoType) as c_int
692}
693
694#[inline]
695/// Check if `op`'s type is exactly `PyDateTimeAPI.TZInfoType`.
696pub unsafe fn PyTZInfo_CheckExact(op: *mut PyObject) -> c_int {
697    (Py_TYPE(op) == (*PyDateTimeAPI()).TZInfoType) as c_int
698}
699
700// skipped non-limited PyDate_FromDate
701// skipped non-limited PyDateTime_FromDateAndTime
702// skipped non-limited PyDateTime_FromDateAndTimeAndFold
703// skipped non-limited PyTime_FromTime
704// skipped non-limited PyTime_FromTimeAndFold
705// skipped non-limited PyDelta_FromDSU
706
707pub unsafe fn PyTimeZone_FromOffset(offset: *mut PyObject) -> *mut PyObject {
708    ((*PyDateTimeAPI()).TimeZone_FromTimeZone)(offset, std::ptr::null_mut())
709}
710
711pub unsafe fn PyTimeZone_FromOffsetAndName(
712    offset: *mut PyObject,
713    name: *mut PyObject,
714) -> *mut PyObject {
715    ((*PyDateTimeAPI()).TimeZone_FromTimeZone)(offset, name)
716}
717
718#[cfg(not(PyPy))]
719pub unsafe fn PyDateTime_FromTimestamp(args: *mut PyObject) -> *mut PyObject {
720    let f = (*PyDateTimeAPI()).DateTime_FromTimestamp;
721    f((*PyDateTimeAPI()).DateTimeType, args, std::ptr::null_mut())
722}
723
724#[cfg(not(PyPy))]
725pub unsafe fn PyDate_FromTimestamp(args: *mut PyObject) -> *mut PyObject {
726    let f = (*PyDateTimeAPI()).Date_FromTimestamp;
727    f((*PyDateTimeAPI()).DateType, args)
728}
729
730#[cfg(PyPy)]
731extern "C" {
732    #[link_name = "PyPyDate_FromTimestamp"]
733    pub fn PyDate_FromTimestamp(args: *mut PyObject) -> *mut PyObject;
734    #[link_name = "PyPyDateTime_FromTimestamp"]
735    pub fn PyDateTime_FromTimestamp(args: *mut PyObject) -> *mut PyObject;
736}
737
738#[cfg(PyPy)]
739extern "C" {
740    #[link_name = "_PyPyDateTime_Import"]
741    pub fn PyDateTime_Import() -> *mut PyDateTime_CAPI;
742}
743
744// Rust specific implementation details
745
746struct PyDateTimeAPISingleton {
747    once: Once,
748    ptr: UnsafeCell<*mut PyDateTime_CAPI>,
749}
750unsafe impl Sync for PyDateTimeAPISingleton {}
751
752static PyDateTimeAPI_impl: PyDateTimeAPISingleton = PyDateTimeAPISingleton {
753    once: Once::new(),
754    ptr: UnsafeCell::new(ptr::null_mut()),
755};
⚠️ Internal Docs ⚠️ Not Public API 👉 Official Docs Here