diff --git a/crates/polars-core/src/chunked_array/logical/datetime.rs b/crates/polars-core/src/chunked_array/logical/datetime.rs index 598e580dbe40..be53ccd19c93 100644 --- a/crates/polars-core/src/chunked_array/logical/datetime.rs +++ b/crates/polars-core/src/chunked_array/logical/datetime.rs @@ -80,23 +80,17 @@ impl LogicalType for DatetimeChunked { .into_series()), }, #[cfg(feature = "dtype-time")] - (Datetime(tu, _), Time) => match tu { - TimeUnit::Nanoseconds => Ok((self.0.as_ref() % NS_IN_DAY) - .cast(&Int64) - .unwrap() + (Datetime(tu, _), Time) => Ok({ + let (modder, multiplier) = match tu { + TimeUnit::Nanoseconds => (NS_IN_DAY, 1i64), + TimeUnit::Microseconds => (US_IN_DAY, 1_000i64), + TimeUnit::Milliseconds => (MS_IN_DAY, 1_000_000i64), + }; + self.0 + .apply_values(|v| (v % modder * multiplier) + (NS_IN_DAY * (v < 0) as i64)) .into_time() - .into_series()), - TimeUnit::Microseconds => Ok((self.0.as_ref() % US_IN_DAY * 1_000i64) - .cast(&Int64) - .unwrap() - .into_time() - .into_series()), - TimeUnit::Milliseconds => Ok((self.0.as_ref() % MS_IN_DAY * 1_000_000i64) - .cast(&Int64) - .unwrap() - .into_time() - .into_series()), - }, + .into_series() + }), _ => self.0.cast(dtype), } } diff --git a/py-polars/tests/unit/namespaces/test_datetime.py b/py-polars/tests/unit/namespaces/test_datetime.py index 20969441e298..66e0665a76d8 100644 --- a/py-polars/tests/unit/namespaces/test_datetime.py +++ b/py-polars/tests/unit/namespaces/test_datetime.py @@ -144,8 +144,18 @@ def test_local_datetime_sortedness(time_zone: str | None, expected: bool) -> Non def test_local_time_sortedness(time_zone: str | None) -> None: ser = (pl.Series([datetime(2022, 1, 1, 23)]).dt.replace_time_zone(time_zone)).sort() result = ser.dt.time() - assert result.flags["SORTED_ASC"] is False - assert result.flags["SORTED_DESC"] is False + assert result.flags["SORTED_ASC"] + assert not result.flags["SORTED_DESC"] + + +@pytest.mark.parametrize("time_unit", ["ms", "us", "ns"]) +def test_local_time_before_epoch(time_unit: TimeUnit) -> None: + ser = pl.Series([datetime(1969, 7, 21, 2, 56, 2, 123000)]).dt.cast_time_unit( + time_unit + ) + result = ser.dt.time().item() + expected = time(2, 56, 2, 123000) + assert result == expected @pytest.mark.parametrize(