Add PyTime component accessors

This commit is contained in:
Paul Ganssle 2018-08-09 11:25:33 -04:00
parent ecf3aaafb2
commit f701bccbdf
No known key found for this signature in database
GPG key ID: CD54FCE3D964BEFB
4 changed files with 129 additions and 11 deletions

View file

@ -108,6 +108,7 @@ pub struct PyDateTime_CAPI {
// Type struct wrappers
const _PyDateTime_DATE_DATASIZE : usize = 4;
const _PyDateTime_TIME_DATASIZE : usize = 6;
const _PyDateTime_DATETIME_DATASIZE: usize = 10;
#[repr(C)]
@ -119,6 +120,18 @@ pub struct PyDateTime_Date {
pub data: [c_uchar; _PyDateTime_DATE_DATASIZE],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct PyDateTime_Time {
pub ob_base: PyObject,
pub hashcode: Py_hash_t,
pub hastzinfo: c_char,
pub data: [c_uchar; _PyDateTime_TIME_DATASIZE],
#[cfg(Py_3_6)]
pub fold: c_uchar,
pub tzinfo: *mut PyObject
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct PyDateTime_DateTime {
@ -324,6 +337,38 @@ pub unsafe fn PyDateTime_DATE_GET_TZINFO(o: *mut PyObject) -> *mut PyObject {
_PyDateTime_GET_TZINFO!(o as *mut PyDateTime_DateTime)
}
// Accessor functions for Time
#[inline(always)]
pub unsafe fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int {
_PyDateTime_GET_HOUR!((o as *mut PyDateTime_Time), 0)
}
#[inline(always)]
pub unsafe fn PyDateTime_TIME_GET_MINUTE(o: *mut PyObject) -> c_int {
_PyDateTime_GET_MINUTE!((o as *mut PyDateTime_Time), 0)
}
#[inline(always)]
pub unsafe fn PyDateTime_TIME_GET_SECOND(o: *mut PyObject) -> c_int {
_PyDateTime_GET_SECOND!((o as *mut PyDateTime_Time), 0)
}
#[inline(always)]
pub unsafe fn PyDateTime_TIME_GET_MICROSECOND(o: *mut PyObject) -> c_int {
_PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_Time), 0)
}
#[cfg(Py_3_6)]
#[inline(always)]
pub unsafe fn PyDateTime_TIME_GET_FOLD(o: *mut PyObject) -> c_uchar {
_PyDateTime_GET_FOLD!(o as *mut PyDateTime_Time)
}
#[inline(always)]
pub unsafe fn PyDateTime_TIME_GET_TZINFO(o: *mut PyObject) -> *mut PyObject {
_PyDateTime_GET_TZINFO!(o as *mut PyDateTime_Time)
}
// Accessor functions for PyDateTime_Delta
macro_rules! _access_delta_field {

View file

@ -6,6 +6,8 @@ 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_TIME_GET_HOUR, PyDateTime_TIME_GET_MINUTE,
PyDateTime_TIME_GET_SECOND, PyDateTime_TIME_GET_MICROSECOND};
use ffi::{PyDateTime_DATE_GET_HOUR, PyDateTime_DATE_GET_MINUTE,
PyDateTime_DATE_GET_SECOND, PyDateTime_DATE_GET_MICROSECOND};
use ffi::{PyDateTime_DeltaType, PyDelta_Check};
@ -14,7 +16,7 @@ use ffi::{PyDateTime_TimeType, PyTime_Check};
use ffi::{PyDateTime_TZInfoType, PyTZInfo_Check};
#[cfg(Py_3_6)]
use ffi::{PyDateTime_DATE_GET_FOLD};
use ffi::{PyDateTime_DATE_GET_FOLD, PyDateTime_TIME_GET_FOLD};
use python::{Python, ToPyPointer};
use instance::Py;
@ -224,6 +226,40 @@ impl PyTime {
}
impl PyTimeComponentAccess for PyTime {
fn get_hour(&self) -> u32 {
unsafe {
PyDateTime_TIME_GET_HOUR(self.as_ptr()) as u32
}
}
fn get_minute(&self) -> u32 {
unsafe {
PyDateTime_TIME_GET_MINUTE(self.as_ptr()) as u32
}
}
fn get_second(&self) -> u32 {
unsafe {
PyDateTime_TIME_GET_SECOND(self.as_ptr()) as u32
}
}
fn get_microsecond(&self) -> u32 {
unsafe {
PyDateTime_TIME_GET_MICROSECOND(self.as_ptr()) as u32
}
}
#[cfg(Py_3_6)]
fn get_fold(&self) -> u8 {
unsafe {
PyDateTime_TIME_GET_FOLD(self.as_ptr()) as u8
}
}
}
// datetime.tzinfo bindings
pub struct PyTzInfo(PyObject);
pyobject_native_type!(PyTzInfo, PyDateTime_TZInfoType, PyTZInfo_Check);

View file

@ -46,6 +46,28 @@ fn make_time(py: Python, hour: u32, minute: u32, second: u32,
PyTime::new(py, hour, minute, second, microsecond, &tzi)
}
#[cfg(Py_3_6)]
#[pyfunction]
fn time_with_fold(py: Python, hour: u32, minute: u32, second: u32,
microsecond: u32, tzinfo: Option<&PyTzInfo>,
fold: bool) -> PyResult<Py<PyTime>> {
let tzi = to_pyobject!(py, tzinfo);
PyTime::new_with_fold(py, hour, minute, second, microsecond, &tzi, fold)
}
#[pyfunction]
fn get_time_tuple(py: Python, dt: &PyTime) -> Py<PyTuple> {
PyTuple::new(py, &[dt.get_hour(), dt.get_minute(), dt.get_second(),
dt.get_microsecond()])
}
#[cfg(Py_3_6)]
#[pyfunction]
fn get_time_tuple_fold(py: Python, dt: &PyTime) -> Py<PyTuple> {
PyTuple::new(py, &[dt.get_hour(), dt.get_minute(), dt.get_second(),
dt.get_microsecond(), dt.get_fold() as u32])
}
#[pyfunction]
fn make_delta(py: Python, days: i32, seconds: i32, microseconds: i32) -> PyResult<Py<PyDelta>> {
PyDelta::new(py, days, seconds, microseconds, true)
@ -97,14 +119,6 @@ fn datetime_from_timestamp(py: Python, ts: f64, tz: Option<&PyTzInfo>) -> PyResu
}
#[cfg(Py_3_6)]
#[pyfunction]
fn time_with_fold(py: Python, hour: u32, minute: u32, second: u32,
microsecond: u32, tzinfo: Option<&PyTzInfo>,
fold: bool) -> PyResult<Py<PyTime>> {
let tzi = to_pyobject!(py, tzinfo);
PyTime::new_with_fold(py, hour, minute, second, microsecond, &tzi, fold)
}
@ -114,6 +128,7 @@ fn datetime(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_function!(get_date_tuple))?;
m.add_function(wrap_function!(date_from_timestamp))?;
m.add_function(wrap_function!(make_time))?;
m.add_function(wrap_function!(get_time_tuple))?;
m.add_function(wrap_function!(make_delta))?;
m.add_function(wrap_function!(get_delta_tuple))?;
m.add_function(wrap_function!(make_datetime))?;
@ -124,6 +139,7 @@ fn datetime(_py: Python, m: &PyModule) -> PyResult<()> {
#[cfg(Py_3_6)]
{
m.add_function(wrap_function!(time_with_fold));
m.add_function(wrap_function!(get_time_tuple_fold));
m.add_function(wrap_function!(get_datetime_tuple_fold));
}

View file

@ -62,6 +62,27 @@ def test_time(args, kwargs):
assert act.tzinfo is exp.tzinfo
@given(t=st.times())
def test_time(t):
act = rdt.get_time_tuple(t)
exp = (t.hour, t.minute, t.second, t.microsecond)
assert act == exp
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
@given(t=st.times())
def test_time_fold(t):
t_nofold = t.replace(fold=0)
t_fold = t.replace(fold=1)
for t in (t_nofold, t_fold):
act = rdt.get_time_tuple_fold(t)
exp = (t.hour, t.minute, t.second, t.microsecond, t.fold)
assert act == exp
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
@pytest.mark.parametrize('fold', [False, True])
def test_time_fold(fold):
@ -130,8 +151,8 @@ def test_datetime_tuple(dt):
@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)
dt_fold = dt.replace(fold=1)
dt_nofold = dt.replace(fold=0)
for dt in (dt_fold, dt_nofold):
act = rdt.get_datetime_tuple_fold(dt)