Skip to content

Commit

Permalink
Panic on bad input
Browse files Browse the repository at this point in the history
  • Loading branch information
mcrumiller committed Jan 30, 2025
1 parent 0bc6cb8 commit 441f14d
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 12 deletions.
6 changes: 4 additions & 2 deletions crates/polars-time/src/chunkedarray/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,10 @@ pub trait DateMethods: AsDate {
.zip(day)
.map(|((y, m), d)| {
if let (Some(y), Some(m), Some(d)) = (y, m, d) {
NaiveDate::from_ymd_opt(y, m as u32, d as u32)
.map(|t| t.num_days_from_ce() - EPOCH_DAYS_FROM_CE)
let Some(ns) = NaiveDate::from_ymd_opt(y, m as u32, d as u32) else {
panic!("Invalid date components ({}, {}, {}) supplied.", y, m, d)
};
Some(ns.num_days_from_ce() - EPOCH_DAYS_FROM_CE)
} else {
None
}
Expand Down
28 changes: 19 additions & 9 deletions crates/polars-time/src/chunkedarray/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,21 +179,31 @@ pub trait DatetimeMethods: AsDatetime {
if let (Some(y), Some(m), Some(d), Some(h), Some(mnt), Some(s), Some(ns)) =
(y, m, d, h, mnt, s, ns)
{
NaiveDate::from_ymd_opt(y, m as u32, d as u32)
.and_then(|nd| {
nd.and_hms_nano_opt(h as u32, mnt as u32, s as u32, ns as u32)
})
.map(|ndt| match time_unit {
TimeUnit::Milliseconds => ndt.and_utc().timestamp_millis(),
TimeUnit::Microseconds => ndt.and_utc().timestamp_micros(),
TimeUnit::Nanoseconds => ndt.and_utc().timestamp_nanos_opt().unwrap(),
})
let Some(t) = NaiveDate::from_ymd_opt(y, m as u32, d as u32) else {
panic!(
"Invalid datetime components ({}, {}, {}, {}, {}, {}, {}) supplied.",
y, m, d, h, mnt, s, ns
)
};
let Some(ndt) = t.and_hms_nano_opt(h as u32, mnt as u32, s as u32, ns as u32)
else {
panic!(
"Invalid datetime components ({}, {}, {}, {}, {}, {}, {}) supplied.",
y, m, d, h, mnt, s, ns
)
};
Some(match time_unit {
TimeUnit::Milliseconds => ndt.and_utc().timestamp_millis(),
TimeUnit::Microseconds => ndt.and_utc().timestamp_micros(),
TimeUnit::Nanoseconds => ndt.and_utc().timestamp_nanos_opt().unwrap(),
})
} else {
None
}
})
.collect_trusted();

println!("here");
let mut ca = match time_zone {
#[cfg(feature = "timezones")]
Some(_) => {
Expand Down
37 changes: 36 additions & 1 deletion py-polars/tests/unit/functions/as_datatype/test_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import pytest

import polars as pl
from polars.exceptions import ComputeError
from polars.exceptions import ComputeError, PanicException
from polars.testing import assert_series_equal

if TYPE_CHECKING:
Expand All @@ -32,6 +32,41 @@ def test_date_datetime() -> None:
assert_series_equal(out["h2"], df["hour"].rename("h2"))


@pytest.mark.parametrize(
"components",
[
[2025, 13, 1],
[2025, 1, 32],
[2025, 2, 29],
],
)
def test_date_invalid_component(components: list[int]) -> None:
y, m, d = components
msg = rf"Invalid datetime components \({y}, {m}, {d}, 0, 0, 0, 0\) supplied."
with pytest.raises(PanicException, match=msg):
pl.select(pl.date(*components))


@pytest.mark.parametrize(
"components",
[
[2025, 13, 1, 0, 0, 0, 0],
[2025, 1, 32, 0, 0, 0, 0],
[2025, 2, 29, 0, 0, 0, 0],
[2025, 1, 1, 25, 0, 0, 0],
[2025, 1, 1, 0, 60, 0, 0],
[2025, 1, 1, 0, 0, 60, 0],
[2025, 1, 1, 0, 0, 0, 2_000_000],
],
)
def test_datetime_invalid_component(components: list[int]) -> None:
y, m, d, h, mnt, s, us = components
ns = us * 1_000
msg = rf"Invalid datetime components \({y}, {m}, {d}, {h}, {mnt}, {s}, {ns}\) supplied."
with pytest.raises(PanicException, match=msg):
pl.select(pl.datetime(*components))


@pytest.mark.parametrize("time_unit", ["ms", "us", "ns"])
def test_datetime_time_unit(time_unit: TimeUnit) -> None:
result = pl.datetime(2022, 1, 2, time_unit=time_unit)
Expand Down

0 comments on commit 441f14d

Please sign in to comment.