1//! Traits and utilities for temporal data.
2pub mod conversion;
3#[cfg(feature = "dtype-date")]
4mod date;
5#[cfg(feature = "dtype-datetime")]
6mod datetime;
7#[cfg(feature = "dtype-duration")]
8mod duration;
9#[cfg(feature = "dtype-time")]
10mod time;
1112#[cfg(feature = "dtype-date")]
13use chrono::NaiveDate;
14use chrono::NaiveDateTime;
15#[cfg(any(feature = "dtype-time", feature = "dtype-date"))]
16use chrono::NaiveTime;
17#[cfg(feature = "timezones")]
18use chrono_tz::Tz;
19#[cfg(feature = "timezones")]
20use polars_utils::pl_str::PlSmallStr;
21#[cfg(feature = "dtype-time")]
22pub use time::time_to_time64ns;
2324pub use self::conversion::*;
25#[cfg(feature = "timezones")]
26use crate::prelude::{PolarsResult, polars_bail};
2728#[cfg(feature = "timezones")]
29static FIXED_OFFSET_PATTERN: &str = r#"(?x)
30 ^
31 (?P<sign>[-+])? # optional sign
32 (?P<hour>0[0-9]|1[0-4]) # hour (between 0 and 14)
33 :? # optional separator
34 00 # minute
35 $
36 "#;
37#[cfg(feature = "timezones")]
38polars_utils::regex_cache::cached_regex! {
39static FIXED_OFFSET_RE = FIXED_OFFSET_PATTERN;
40}
4142#[cfg(feature = "timezones")]
43pub fn validate_time_zone(tz: &str) -> PolarsResult<()> {
44match tz.parse::<Tz>() {
45Ok(_) => Ok(()),
46Err(_) => {
47polars_bail!(ComputeError: "unable to parse time zone: '{}'. Please check the Time Zone Database for a list of available time zones", tz)
48 },
49 }
50}
5152#[cfg(feature = "timezones")]
53pub fn parse_time_zone(tz: &str) -> PolarsResult<Tz> {
54match tz.parse::<Tz>() {
55Ok(tz) => Ok(tz),
56Err(_) => {
57polars_bail!(ComputeError: "unable to parse time zone: '{}'. Please check the Time Zone Database for a list of available time zones", tz)
58 },
59 }
60}
6162/// Convert fixed offset to Etc/GMT one from time zone database
63///
64/// E.g. +01:00 -> Etc/GMT-1
65///
66/// Note: the sign appears reversed, but is correct, see <https://en.wikipedia.org/wiki/Tz_database#Area>:
67/// > In order to conform with the POSIX style, those zone names beginning with
68/// > "Etc/GMT" have their sign reversed from the standard ISO 8601 convention.
69/// > In the "Etc" area, zones west of GMT have a positive sign and those east
70/// > have a negative sign in their name (e.g "Etc/GMT-14" is 14 hours ahead of GMT).
71#[cfg(feature = "timezones")]
72pub fn parse_fixed_offset(tz: &str) -> PolarsResult<PlSmallStr> {
73use polars_utils::format_pl_smallstr;
7475if let Some(caps) = FIXED_OFFSET_RE.captures(tz) {
76let sign = match caps.name("sign").map(|s| s.as_str()) {
77Some("-") => "+",
78_ => "-",
79 };
80let hour = caps.name("hour").unwrap().as_str().parse::<i32>().unwrap();
81let etc_tz = format_pl_smallstr!("Etc/GMT{}{}", sign, hour);
82if etc_tz.parse::<Tz>().is_ok() {
83return Ok(etc_tz);
84 }
85 }
86polars_bail!(ComputeError: "unable to parse time zone: '{}'. Please check the Time Zone Database for a list of available time zones", tz)
87}