Skip to content

Commit

Permalink
fix: .dt.time() was panicking for datetimes prior to unix epoch (#13812)
Browse files Browse the repository at this point in the history
Co-authored-by: Marshall Crumiller <mcrumiller@gmail.com>
  • Loading branch information
MarcoGorelli and mcrumiller authored Jan 20, 2024
1 parent 0ec95d2 commit 6eb4db5
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 18 deletions.
26 changes: 10 additions & 16 deletions crates/polars-core/src/chunked_array/logical/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}
Expand Down
14 changes: 12 additions & 2 deletions py-polars/tests/unit/namespaces/test_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,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(
Expand Down

0 comments on commit 6eb4db5

Please sign in to comment.