polars_core/chunked_array/temporal/
time.rs

1use std::fmt::Write;
2
3use arrow::temporal_conversions::{time64ns_to_time, NANOSECONDS};
4use chrono::Timelike;
5
6use super::*;
7use crate::prelude::*;
8
9const SECONDS_IN_MINUTE: i64 = 60;
10const SECONDS_IN_HOUR: i64 = 3_600;
11
12pub fn time_to_time64ns(time: &NaiveTime) -> i64 {
13    (time.hour() as i64 * SECONDS_IN_HOUR
14        + time.minute() as i64 * SECONDS_IN_MINUTE
15        + time.second() as i64)
16        * NANOSECONDS
17        + time.nanosecond() as i64
18}
19
20impl TimeChunked {
21    /// Convert from Time into String with the given format.
22    /// See [chrono strftime/strptime](https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html).
23    pub fn to_string(&self, format: &str) -> StringChunked {
24        let mut ca: StringChunked = self.apply_kernel_cast(&|arr| {
25            let mut buf = String::new();
26            let format = if format == "iso" || format == "iso:strict" {
27                "%T%.9f"
28            } else {
29                format
30            };
31            let mut mutarr = MutablePlString::with_capacity(arr.len());
32
33            for opt in arr.into_iter() {
34                match opt {
35                    None => mutarr.push_null(),
36                    Some(v) => {
37                        buf.clear();
38                        let timefmt = time64ns_to_time(*v).format(format);
39                        write!(buf, "{timefmt}").unwrap();
40                        mutarr.push_value(&buf)
41                    },
42                }
43            }
44
45            mutarr.freeze().boxed()
46        });
47
48        ca.rename(self.name().clone());
49        ca
50    }
51
52    /// Convert from Time into String with the given format.
53    /// See [chrono strftime/strptime](https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html).
54    ///
55    /// Alias for `to_string`.
56    pub fn strftime(&self, format: &str) -> StringChunked {
57        self.to_string(format)
58    }
59
60    pub fn as_time_iter(&self) -> impl TrustedLen<Item = Option<NaiveTime>> + '_ {
61        // we know the iterators len
62        unsafe {
63            self.downcast_iter()
64                .flat_map(|iter| {
65                    iter.into_iter()
66                        .map(|opt_v| opt_v.copied().map(time64ns_to_time))
67                })
68                .trust_my_length(self.len())
69        }
70    }
71
72    /// Construct a new [`TimeChunked`] from an iterator over [`NaiveTime`].
73    pub fn from_naive_time<I: IntoIterator<Item = NaiveTime>>(name: PlSmallStr, v: I) -> Self {
74        let vals = v
75            .into_iter()
76            .map(|nt| time_to_time64ns(&nt))
77            .collect::<Vec<_>>();
78        Int64Chunked::from_vec(name, vals).into_time()
79    }
80
81    /// Construct a new [`TimeChunked`] from an iterator over optional [`NaiveTime`].
82    pub fn from_naive_time_options<I: IntoIterator<Item = Option<NaiveTime>>>(
83        name: PlSmallStr,
84        v: I,
85    ) -> Self {
86        let vals = v.into_iter().map(|opt| opt.map(|nt| time_to_time64ns(&nt)));
87        Int64Chunked::from_iter_options(name, vals).into_time()
88    }
89}