Add datetime.time

This commit is contained in:
Paul Ganssle 2018-04-08 10:28:20 -04:00
parent d7b90c1b3a
commit f45362943d
No known key found for this signature in database
GPG Key ID: CD54FCE3D964BEFB
5 changed files with 96 additions and 3 deletions

View File

@ -130,3 +130,8 @@ pub unsafe fn PyDateTime_Check(op: *mut PyObject) -> c_int {
pub unsafe fn PyTZInfo_Check(op: *mut PyObject) -> c_int { pub unsafe fn PyTZInfo_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.TZInfoType) as c_int PyObject_TypeCheck(op, PyDateTimeAPI.TZInfoType) as c_int
} }
#[inline(always)]
pub unsafe fn PyTime_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.TimeType) as c_int
}

View File

@ -54,6 +54,29 @@ impl PyDateTime {
} }
} }
// datetime.time
pub struct PyTime(PyObject);
pyobject_convert!(PyTime);
pyobject_nativetype!(PyTime, PyDateTime_TimeType, PyTime_Check);
impl PyTime {
pub fn new(py: Python, hour: u32, minute: u32, second: u32,
microsecond: u32, tzinfo: &PyObject) -> PyResult<Py<PyTime>> {
let h = hour as c_int;
let m = minute as c_int;
let s = second as c_int;
let u = microsecond as c_int;
let tzi = tzinfo.as_ptr();
unsafe {
let ptr = PyDateTimeAPI.Time_FromTime.unwrap()(
h, m, s, u, tzi, PyDateTimeAPI.TimeType
);
Py::from_owned_ptr_or_err(py, ptr)
}
}
}
// datetime.tzinfo bindings // datetime.tzinfo bindings
pub struct PyTzInfo(PyObject); pub struct PyTzInfo(PyObject);
pyobject_convert!(PyTzInfo); pyobject_convert!(PyTzInfo);

View File

@ -5,7 +5,7 @@ mod exc_impl;
pub use self::boolobject::PyBool; pub use self::boolobject::PyBool;
pub use self::bytearray::PyByteArray; pub use self::bytearray::PyByteArray;
pub use self::datetime::{PyDate,PyDateTime,PyTzInfo}; pub use self::datetime::{PyDate,PyTime,PyDateTime,PyTzInfo};
pub use self::dict::PyDict; pub use self::dict::PyDict;
pub use self::floatob::PyFloat; pub use self::floatob::PyFloat;
pub use self::iterator::PyIterator; pub use self::iterator::PyIterator;

View File

@ -4,7 +4,7 @@ extern crate pyo3;
use pyo3::{py, Py, Python, PyModule, PyResult}; use pyo3::{py, Py, Python, PyModule, PyResult};
use pyo3::{ToPyObject}; use pyo3::{ToPyObject};
use pyo3::prelude::{PyObject}; use pyo3::prelude::{PyObject};
use pyo3::prelude::{PyDate, PyDateTime, PyTzInfo}; use pyo3::prelude::{PyDate, PyTime, PyDateTime, PyTzInfo};
#[py::modinit(datetime)] #[py::modinit(datetime)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> { fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
@ -13,6 +13,17 @@ fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
PyDate::new(py, year, month, day) PyDate::new(py, year, month, day)
} }
#[pyfn(m, "make_time")]
fn make_time(py: Python, hour: u32, minute: u32, second: u32,
microsecond: u32, tzinfo: Option<&PyTzInfo>) -> PyResult<Py<PyTime>> {
let tzi: PyObject = match tzinfo {
Some(t) => t.to_object(py),
None => py.None(),
};
PyTime::new(py, hour, minute, second, microsecond, &tzi)
}
#[pyfn(m, "make_datetime")] #[pyfn(m, "make_datetime")]
fn make_datetime(py: Python, year: u32, month: u32, day: u32, fn make_datetime(py: Python, year: u32, month: u32, day: u32,
hour: u32, minute: u32, second: u32, microsecond: u32, hour: u32, minute: u32, second: u32, microsecond: u32,

View File

@ -4,6 +4,8 @@ import datetime as pdt
import pytest import pytest
UTC = pdt.timezone.utc
def test_date(): def test_date():
assert rdt.make_date(2017, 9, 1) == pdt.date(2017, 9, 1) assert rdt.make_date(2017, 9, 1) == pdt.date(2017, 9, 1)
@ -14,15 +16,67 @@ def test_invalid_date_fails():
rdt.make_date(2017, 2, 30) rdt.make_date(2017, 2, 30)
@pytest.mark.parametrize('args, kwargs', [
((0, 0, 0, 0, None), {}),
((1, 12, 14, 124731), {}),
((1, 12, 14, 124731), {'tzinfo': UTC}),
])
def test_time(args, kwargs):
act = rdt.make_time(*args, **kwargs)
exp = pdt.time(*args, **kwargs)
assert act == exp
assert act.tzinfo is exp.tzinfo
@pytest.mark.xfail
@pytest.mark.parametrize('args', [
(-1, 0, 0, 0),
(0, -1, 0, 0),
(0, 0, -1, 0),
(0, 0, 0, -1),
])
def test_invalid_time_fails_xfail(args):
with pytest.raises(ValueError):
rdt.make_time(*args)
@pytest.mark.parametrize('args', [
(24, 0, 0, 0),
(25, 0, 0, 0),
(0, 60, 0, 0),
(0, 61, 0, 0),
(0, 0, 60, 0),
(0, 0, 61, 0),
(0, 0, 0, 1000000)
])
def test_invalid_time_fails(args):
with pytest.raises(ValueError):
rdt.make_time(*args)
@pytest.mark.parametrize('args', [
('0', 0, 0, 0),
(0, '0', 0, 0),
(0, 0, '0', 0),
(0, 0, 0, '0'),
(0, 0, 0, 0, 'UTC')
])
def test_time_typeerror(args):
with pytest.raises(TypeError):
rdt.make_time(*args)
@pytest.mark.parametrize('args, kwargs', [ @pytest.mark.parametrize('args, kwargs', [
((2017, 9, 1, 12, 45, 30, 0), {}), ((2017, 9, 1, 12, 45, 30, 0), {}),
((2017, 9, 1, 12, 45, 30, 0), {'tzinfo': pdt.timezone.utc}), ((2017, 9, 1, 12, 45, 30, 0), {'tzinfo': UTC}),
]) ])
def test_datetime(args, kwargs): def test_datetime(args, kwargs):
act = rdt.make_datetime(*args, **kwargs) act = rdt.make_datetime(*args, **kwargs)
exp = pdt.datetime(*args, **kwargs) exp = pdt.datetime(*args, **kwargs)
assert act == exp assert act == exp
assert act.tzinfo is exp.tzinfo
def test_invalid_datetime_fails(): def test_invalid_datetime_fails():