Skip to content

Commit 3165513

Browse files
committed
fix ValueError on year zero
1 parent 6eee20d commit 3165513

File tree

5 files changed

+66
-30
lines changed

5 files changed

+66
-30
lines changed

src/input/datetime.rs

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,32 @@ pub fn pydate_as_date(py_date: &Bound<'_, PyAny>) -> PyResult<Date> {
4545
})
4646
}
4747

48-
impl EitherDate<'_> {
48+
impl<'py> EitherDate<'py> {
49+
pub fn try_into_py(self, py: Python<'py>, input: &(impl Input<'py> + ?Sized)) -> ValResult<PyObject> {
50+
match self {
51+
Self::Raw(date) => {
52+
if date.year == 0 {
53+
return Err(ValError::new(
54+
ErrorType::DateParsing {
55+
error: Cow::Borrowed("year 0 is out of range"),
56+
context: None,
57+
},
58+
input,
59+
));
60+
};
61+
let py_date = PyDate::new_bound(py, date.year.into(), date.month, date.day)?;
62+
Ok(py_date.into())
63+
}
64+
Self::Py(py_date) => Ok(py_date.into()),
65+
}
66+
}
67+
4968
pub fn as_raw(&self) -> PyResult<Date> {
5069
match self {
5170
Self::Raw(date) => Ok(date.clone()),
5271
Self::Py(py_date) => pydate_as_date(py_date),
5372
}
5473
}
55-
56-
pub fn try_into_py(self, py: Python<'_>) -> PyResult<PyObject> {
57-
let date = match self {
58-
Self::Py(date) => Ok(date),
59-
Self::Raw(date) => PyDate::new_bound(py, date.year.into(), date.month, date.day),
60-
}?;
61-
Ok(date.into_py(py))
62-
}
6374
}
6475

6576
#[cfg_attr(debug_assertions, derive(Debug))]
@@ -259,31 +270,42 @@ pub fn pydatetime_as_datetime(py_dt: &Bound<'_, PyAny>) -> PyResult<DateTime> {
259270
})
260271
}
261272

262-
impl<'a> EitherDateTime<'a> {
273+
impl<'py> EitherDateTime<'py> {
274+
pub fn try_into_py(self, py: Python<'py>, input: &(impl Input<'py> + ?Sized)) -> ValResult<PyObject> {
275+
match self {
276+
Self::Raw(dt) => {
277+
if dt.date.year == 0 {
278+
return Err(ValError::new(
279+
ErrorType::DatetimeParsing {
280+
error: Cow::Borrowed("year 0 is out of range"),
281+
context: None,
282+
},
283+
input,
284+
));
285+
};
286+
let py_dt = PyDateTime::new_bound(
287+
py,
288+
dt.date.year.into(),
289+
dt.date.month,
290+
dt.date.day,
291+
dt.time.hour,
292+
dt.time.minute,
293+
dt.time.second,
294+
dt.time.microsecond,
295+
time_as_tzinfo(py, &dt.time)?.as_ref(),
296+
)?;
297+
Ok(py_dt.into())
298+
}
299+
Self::Py(py_dt) => Ok(py_dt.into()),
300+
}
301+
}
302+
263303
pub fn as_raw(&self) -> PyResult<DateTime> {
264304
match self {
265305
Self::Raw(dt) => Ok(dt.clone()),
266306
Self::Py(py_dt) => pydatetime_as_datetime(py_dt),
267307
}
268308
}
269-
270-
pub fn try_into_py(self, py: Python<'a>) -> PyResult<PyObject> {
271-
let dt = match self {
272-
Self::Raw(datetime) => PyDateTime::new_bound(
273-
py,
274-
datetime.date.year.into(),
275-
datetime.date.month,
276-
datetime.date.day,
277-
datetime.time.hour,
278-
datetime.time.minute,
279-
datetime.time.second,
280-
datetime.time.microsecond,
281-
time_as_tzinfo(py, &datetime.time)?.as_ref(),
282-
)?,
283-
Self::Py(dt) => dt.clone(),
284-
};
285-
Ok(dt.into_py(py))
286-
}
287309
}
288310

289311
pub fn bytes_as_date<'py>(input: &(impl Input<'py> + ?Sized), bytes: &[u8]) -> ValResult<EitherDate<'py>> {

src/validators/date.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ impl Validator for DateValidator {
9797
}
9898
}
9999
}
100-
Ok(date.try_into_py(py)?)
100+
date.try_into_py(py, input)
101101
}
102102

103103
fn get_name(&self) -> &str {

src/validators/datetime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ impl Validator for DateTimeValidator {
130130
tz_constraint.tz_check(speedate_dt.time.tz_offset, input)?;
131131
}
132132
}
133-
Ok(datetime.try_into_py(py)?)
133+
datetime.try_into_py(py, input)
134134
}
135135

136136
fn get_name(&self) -> &str {

tests/validators/test_date.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@
6464
),
6565
pytest.param('-', Err('Input should be a valid date or datetime, input is too short'), id='minus'),
6666
pytest.param('+', Err('Input should be a valid date or datetime, input is too short'), id='pus'),
67+
pytest.param('0001-01-01', date(1, 1, 1), id='min-date'),
68+
pytest.param(
69+
'0000-12-31',
70+
Err('Input should be a valid date in the format YYYY-MM-DD, year 0 is out of range [type=date_parsing,'),
71+
id='year-0',
72+
),
6773
],
6874
)
6975
def test_date(input_value, expected):

tests/validators/test_datetime.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@
5353
'Input should be a valid datetime or date, day value is outside expected range [type=datetime_from_date_parsing,'
5454
),
5555
),
56+
(
57+
'0001-01-01T00:00:00.000000Z',
58+
datetime(1, 1, 1, tzinfo=timezone.utc),
59+
),
60+
(
61+
'0000-12-31T23:59:59.999999Z',
62+
Err('Input should be a valid datetime, year 0 is out of range [type=datetime_parsing,'),
63+
),
5664
],
5765
)
5866
def test_datetime(input_value, expected):

0 commit comments

Comments
 (0)