polars_time/
utils.rs

1#[cfg(feature = "timezones")]
2use arrow::legacy::kernels::{
3    Ambiguous, NonExistent, convert_to_naive_local, convert_to_naive_local_opt,
4};
5#[cfg(feature = "timezones")]
6use arrow::legacy::time_zone::Tz;
7#[cfg(feature = "timezones")]
8use chrono::NaiveDateTime;
9#[cfg(feature = "timezones")]
10use chrono::TimeZone;
11#[cfg(feature = "timezones")]
12use chrono_tz::TZ_VARIANTS;
13#[cfg(feature = "timezones")]
14use polars_core::prelude::PolarsResult;
15
16/// Localize datetime according to given time zone.
17///
18/// e.g. '2021-01-01 03:00' -> '2021-01-01 03:00CDT'
19///
20/// Note: this may only return `Ok(None)` if ambiguous is Ambiguous::Null
21/// or if non_existent is NonExistent::Null.
22/// Otherwise, it will either return `Ok(Some(NaiveDateTime))` or `PolarsError`.
23///
24/// Therefore, calling `try_localize_datetime(..., Ambiguous::Raise, NonExistent::Raise)?.unwrap()`
25/// is safe, and will never panic.
26#[cfg(feature = "timezones")]
27pub(crate) fn try_localize_datetime(
28    ndt: NaiveDateTime,
29    tz: &Tz,
30    ambiguous: Ambiguous,
31    non_existent: NonExistent,
32) -> PolarsResult<Option<NaiveDateTime>> {
33    convert_to_naive_local(&chrono_tz::UTC, tz, ndt, ambiguous, non_existent)
34}
35
36#[cfg(feature = "timezones")]
37pub(crate) fn localize_datetime_opt(
38    ndt: NaiveDateTime,
39    tz: &Tz,
40    ambiguous: Ambiguous,
41) -> Option<Option<NaiveDateTime>> {
42    // e.g. '2021-01-01 03:00' -> '2021-01-01 03:00CDT'
43    convert_to_naive_local_opt(&chrono_tz::UTC, tz, ndt, ambiguous)
44}
45
46#[cfg(feature = "timezones")]
47pub(crate) fn unlocalize_datetime(ndt: NaiveDateTime, tz: &Tz) -> NaiveDateTime {
48    // e.g. '2021-01-01 03:00CDT' -> '2021-01-01 03:00'
49    tz.from_utc_datetime(&ndt).naive_local()
50}
51
52#[cfg(feature = "timezones")]
53pub fn known_timezones() -> [&'static str; TZ_VARIANTS.len()] {
54    core::array::from_fn(|i| TZ_VARIANTS[i].name())
55}