Add PyDateTime component accessors
This commit is contained in:
parent
0b39452276
commit
ecf3aaafb2
|
@ -108,6 +108,7 @@ pub struct PyDateTime_CAPI {
|
|||
// Type struct wrappers
|
||||
|
||||
const _PyDateTime_DATE_DATASIZE : usize = 4;
|
||||
const _PyDateTime_DATETIME_DATASIZE: usize = 10;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
@ -118,6 +119,18 @@ pub struct PyDateTime_Date {
|
|||
pub data: [c_uchar; _PyDateTime_DATE_DATASIZE],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct PyDateTime_DateTime {
|
||||
pub ob_base: PyObject,
|
||||
pub hashcode: Py_hash_t,
|
||||
pub hastzinfo: c_char,
|
||||
pub data: [c_uchar; _PyDateTime_DATETIME_DATASIZE],
|
||||
#[cfg(Py_3_6)]
|
||||
pub fold: c_uchar,
|
||||
pub tzinfo: *mut PyObject
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct PyDateTime_Delta {
|
||||
|
@ -200,6 +213,11 @@ pub unsafe fn PyDateTime_Date_GET_YEAR(o: *mut PyObject) -> c_int {
|
|||
PyDateTime_GET_YEAR!(o as *mut PyDateTime_Date)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyDateTime_DateTime_GET_YEAR(o: *mut PyObject) -> c_int {
|
||||
PyDateTime_GET_YEAR!(o as *mut PyDateTime_DateTime)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! PyDateTime_GET_MONTH {
|
||||
($o: expr) => {
|
||||
|
@ -212,6 +230,11 @@ pub unsafe fn PyDateTime_Date_GET_MONTH(o: *mut PyObject) -> c_int {
|
|||
PyDateTime_GET_MONTH!(o as *mut PyDateTime_Date)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyDateTime_DateTime_GET_MONTH(o: *mut PyObject) -> c_int {
|
||||
PyDateTime_GET_MONTH!(o as *mut PyDateTime_DateTime)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! PyDateTime_GET_DAY {
|
||||
($o: expr) => {
|
||||
|
@ -219,12 +242,88 @@ macro_rules! PyDateTime_GET_DAY {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyDateTime_Date_GET_DAY(o: *mut PyObject) -> c_int {
|
||||
PyDateTime_GET_DAY!(o as *mut PyDateTime_Date)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyDateTime_DateTime_GET_DAY(o: *mut PyObject) -> c_int {
|
||||
PyDateTime_GET_DAY!(o as *mut PyDateTime_DateTime)
|
||||
}
|
||||
|
||||
// Accessor macros for times
|
||||
macro_rules! _PyDateTime_GET_HOUR {
|
||||
($o: expr, $offset:expr) => {
|
||||
(*$o).data[$offset + 0] as c_int
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! _PyDateTime_GET_MINUTE {
|
||||
($o: expr, $offset:expr) => {
|
||||
(*$o).data[$offset + 1] as c_int
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! _PyDateTime_GET_SECOND {
|
||||
($o: expr, $offset:expr) => {
|
||||
(*$o).data[$offset + 2] as c_int
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! _PyDateTime_GET_MICROSECOND {
|
||||
($o: expr, $offset:expr) => {
|
||||
(((*$o).data[$offset + 3] as c_int) << 16) |
|
||||
(((*$o).data[$offset + 4] as c_int) << 8) |
|
||||
((*$o).data[$offset + 5] as c_int)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
macro_rules! _PyDateTime_GET_FOLD{
|
||||
($o: expr) => {
|
||||
(*$o).fold
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! _PyDateTime_GET_TZINFO{
|
||||
($o: expr) => {
|
||||
(*$o).tzinfo
|
||||
}
|
||||
}
|
||||
|
||||
// Accessor functions for DateTime
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyDateTime_DATE_GET_HOUR(o: *mut PyObject) -> c_int {
|
||||
_PyDateTime_GET_HOUR!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyDateTime_DATE_GET_MINUTE(o: *mut PyObject) -> c_int {
|
||||
_PyDateTime_GET_MINUTE!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyDateTime_DATE_GET_SECOND(o: *mut PyObject) -> c_int {
|
||||
_PyDateTime_GET_SECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyDateTime_DATE_GET_MICROSECOND(o: *mut PyObject) -> c_int {
|
||||
_PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyDateTime_DATE_GET_FOLD(o: *mut PyObject) -> c_uchar {
|
||||
_PyDateTime_GET_FOLD!(o as *mut PyDateTime_DateTime)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyDateTime_DATE_GET_TZINFO(o: *mut PyObject) -> *mut PyObject {
|
||||
_PyDateTime_GET_TZINFO!(o as *mut PyDateTime_DateTime)
|
||||
}
|
||||
|
||||
|
||||
// Accessor functions for PyDateTime_Delta
|
||||
macro_rules! _access_delta_field {
|
||||
|
|
|
@ -5,10 +5,17 @@ use ffi::{PyDateTimeAPI};
|
|||
use ffi::{PyDateTime_DateType, PyDate_Check};
|
||||
use ffi::{PyDateTime_Date_GET_YEAR, PyDateTime_Date_GET_MONTH, PyDateTime_Date_GET_DAY};
|
||||
use ffi::{PyDateTime_DateTimeType, PyDateTime_Check};
|
||||
use ffi::{PyDateTime_DateTime_GET_YEAR, PyDateTime_DateTime_GET_MONTH, PyDateTime_DateTime_GET_DAY};
|
||||
use ffi::{PyDateTime_DATE_GET_HOUR, PyDateTime_DATE_GET_MINUTE,
|
||||
PyDateTime_DATE_GET_SECOND, PyDateTime_DATE_GET_MICROSECOND};
|
||||
use ffi::{PyDateTime_DeltaType, PyDelta_Check};
|
||||
use ffi::{PyDateTime_DELTA_GET_DAYS, PyDateTime_DELTA_GET_SECONDS, PyDateTime_DELTA_GET_MICROSECONDS};
|
||||
use ffi::{PyDateTime_TimeType, PyTime_Check};
|
||||
use ffi::{PyDateTime_TZInfoType, PyTZInfo_Check};
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
use ffi::{PyDateTime_DATE_GET_FOLD};
|
||||
|
||||
use python::{Python, ToPyPointer};
|
||||
use instance::Py;
|
||||
|
||||
|
@ -26,6 +33,16 @@ pub trait PyDeltaComponentAccess {
|
|||
}
|
||||
|
||||
|
||||
pub trait PyTimeComponentAccess {
|
||||
fn get_hour(&self) -> u32;
|
||||
fn get_minute(&self) -> u32;
|
||||
fn get_second(&self) -> u32;
|
||||
fn get_microsecond(&self) -> u32;
|
||||
#[cfg(Py_3_6)]
|
||||
fn get_fold(&self) -> u8;
|
||||
}
|
||||
|
||||
|
||||
// datetime.date bindings
|
||||
pub struct PyDate(PyObject);
|
||||
pyobject_native_type!(PyDate, PyDateTime_DateType, PyDate_Check);
|
||||
|
@ -73,6 +90,7 @@ impl PyDateComponentAccess for PyDate {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// datetime.datetime bindings
|
||||
pub struct PyDateTime(PyObject);
|
||||
pyobject_native_type!(PyDateTime, PyDateTime_DateTimeType, PyDateTime_Check);
|
||||
|
@ -108,8 +126,63 @@ impl PyDateTime {
|
|||
Py::from_owned_ptr_or_err(py, ptr)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl PyDateComponentAccess for PyDateTime {
|
||||
fn get_year(&self) -> u32 {
|
||||
unsafe {
|
||||
PyDateTime_DateTime_GET_YEAR(self.as_ptr()) as u32
|
||||
}
|
||||
}
|
||||
|
||||
fn get_month(&self) -> u32 {
|
||||
unsafe {
|
||||
PyDateTime_DateTime_GET_MONTH(self.as_ptr()) as u32
|
||||
}
|
||||
}
|
||||
|
||||
fn get_day(&self) -> u32 {
|
||||
unsafe {
|
||||
PyDateTime_DateTime_GET_DAY(self.as_ptr()) as u32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PyTimeComponentAccess for PyDateTime {
|
||||
fn get_hour(&self) -> u32 {
|
||||
unsafe {
|
||||
PyDateTime_DATE_GET_HOUR(self.as_ptr()) as u32
|
||||
}
|
||||
}
|
||||
|
||||
fn get_minute(&self) -> u32 {
|
||||
unsafe {
|
||||
PyDateTime_DATE_GET_MINUTE(self.as_ptr()) as u32
|
||||
}
|
||||
}
|
||||
|
||||
fn get_second(&self) -> u32 {
|
||||
unsafe {
|
||||
PyDateTime_DATE_GET_SECOND(self.as_ptr()) as u32
|
||||
}
|
||||
}
|
||||
|
||||
fn get_microsecond(&self) -> u32 {
|
||||
unsafe {
|
||||
PyDateTime_DATE_GET_MICROSECOND(self.as_ptr()) as u32
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
fn get_fold(&self) -> u8 {
|
||||
unsafe {
|
||||
PyDateTime_DATE_GET_FOLD(self.as_ptr()) as u8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// datetime.time
|
||||
pub struct PyTime(PyObject);
|
||||
pyobject_native_type!(PyTime, PyDateTime_TimeType, PyTime_Check);
|
||||
|
|
|
@ -6,7 +6,7 @@ mod exc_impl;
|
|||
pub use self::boolobject::PyBool;
|
||||
pub use self::bytearray::PyByteArray;
|
||||
pub use self::datetime::{PyDate, PyTime, PyDateTime, PyDelta, PyTzInfo};
|
||||
pub use self::datetime::{PyDateComponentAccess};
|
||||
pub use self::datetime::{PyDateComponentAccess, PyTimeComponentAccess};
|
||||
pub use self::datetime::{PyDeltaComponentAccess};
|
||||
pub use self::dict::PyDict;
|
||||
pub use self::floatob::PyFloat;
|
||||
|
|
|
@ -9,7 +9,7 @@ use pyo3::prelude::{pyfunction, pymodinit};
|
|||
use pyo3::prelude::{PyObject};
|
||||
use pyo3::prelude::{PyModule};
|
||||
use pyo3::prelude::{PyDate, PyTime, PyDateTime, PyDelta, PyTzInfo};
|
||||
use pyo3::prelude::{PyDateComponentAccess};
|
||||
use pyo3::prelude::{PyDateComponentAccess, PyTimeComponentAccess};
|
||||
use pyo3::prelude::{PyDeltaComponentAccess};
|
||||
use pyo3::prelude::{PyTuple, PyDict};
|
||||
|
||||
|
@ -67,6 +67,21 @@ fn make_datetime(py: Python, year: u32, month: u32, day: u32,
|
|||
PyDateTime::new(py, year, month, day, hour, minute, second, microsecond, &tzi)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_datetime_tuple(py: Python, dt: &PyDateTime) -> Py<PyTuple> {
|
||||
PyTuple::new(py, &[dt.get_year(), dt.get_month(), dt.get_day(),
|
||||
dt.get_hour(), dt.get_minute(), dt.get_second(),
|
||||
dt.get_microsecond()])
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
#[pyfunction]
|
||||
fn get_datetime_tuple_fold(py: Python, dt: &PyDateTime) -> Py<PyTuple> {
|
||||
PyTuple::new(py, &[dt.get_year(), dt.get_month(), dt.get_day(),
|
||||
dt.get_hour(), dt.get_minute(), dt.get_second(),
|
||||
dt.get_microsecond(), dt.get_fold() as u32])
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn datetime_from_timestamp(py: Python, ts: f64, tz: Option<&PyTzInfo>) -> PyResult<Py<PyDateTime>> {
|
||||
let timestamp : PyObject = ts.to_object(py);
|
||||
|
@ -102,12 +117,14 @@ fn datetime(_py: Python, m: &PyModule) -> PyResult<()> {
|
|||
m.add_function(wrap_function!(make_delta))?;
|
||||
m.add_function(wrap_function!(get_delta_tuple))?;
|
||||
m.add_function(wrap_function!(make_datetime))?;
|
||||
m.add_function(wrap_function!(get_datetime_tuple))?;
|
||||
m.add_function(wrap_function!(datetime_from_timestamp))?;
|
||||
|
||||
// Python 3.6+ functions
|
||||
#[cfg(Py_3_6)]
|
||||
{
|
||||
m.add_function(wrap_function!(time_with_fold));
|
||||
m.add_function(wrap_function!(get_datetime_tuple_fold));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -119,6 +119,26 @@ def test_datetime(args, kwargs):
|
|||
assert act.tzinfo is exp.tzinfo
|
||||
|
||||
|
||||
@given(dt=st.datetimes())
|
||||
def test_datetime_tuple(dt):
|
||||
act = rdt.get_datetime_tuple(dt)
|
||||
exp = dt.timetuple()[0:6] + (dt.microsecond, )
|
||||
|
||||
assert act == exp
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
|
||||
@given(dt=st.datetimes())
|
||||
def test_datetime_tuple_fold(dt):
|
||||
dt_fold = dt.replace(fold=0)
|
||||
dt_nofold = dt.replace(fold=1)
|
||||
|
||||
for dt in (dt_fold, dt_nofold):
|
||||
act = rdt.get_datetime_tuple_fold(dt)
|
||||
exp = dt.timetuple()[0:6] + (dt.microsecond, dt.fold)
|
||||
|
||||
assert act == exp
|
||||
|
||||
def test_invalid_datetime_fails():
|
||||
with pytest.raises(ValueError):
|
||||
rdt.make_datetime(2011, 1, 42, 0, 0, 0, 0)
|
||||
|
|
Loading…
Reference in a new issue