Skip to main content

teaql_tool_std/
time.rs

1use chrono::{DateTime, Datelike, Duration, Months, NaiveDate, TimeZone, Utc};
2use chrono_tz::Tz;
3use std::str::FromStr;
4use teaql_tool_core::{MustPurpose, Result, TeaQLToolError};
5
6pub struct TimeTool;
7
8impl TimeTool {
9    pub fn new() -> Self {
10        Self
11    }
12
13    pub fn now(&self) -> MustPurpose<DateTime<Utc>> {
14        MustPurpose::new(Utc::now())
15    }
16
17    pub fn today(&self) -> MustPurpose<NaiveDate> {
18        MustPurpose::new(Utc::now().date_naive())
19    }
20
21    pub fn parse_date(&self, s: &str) -> Result<MustPurpose<NaiveDate>> {
22        NaiveDate::from_str(s)
23            .map(MustPurpose::new)
24            .map_err(|e| TeaQLToolError::ParseError(e.to_string()))
25    }
26
27    pub fn parse_datetime(&self, s: &str) -> Result<MustPurpose<DateTime<Utc>>> {
28        s.parse::<DateTime<Utc>>()
29            .map(MustPurpose::new)
30            .map_err(|e| TeaQLToolError::ParseError(e.to_string()))
31    }
32
33    pub fn add_days(&self, dt: DateTime<Utc>, days: i64) -> MustPurpose<DateTime<Utc>> {
34        MustPurpose::new(dt + Duration::days(days))
35    }
36
37    pub fn add_months(&self, dt: DateTime<Utc>, months: u32) -> MustPurpose<DateTime<Utc>> {
38        MustPurpose::new(dt.checked_add_months(Months::new(months)).unwrap_or(dt))
39    }
40
41    pub fn start_of_day(&self, dt: DateTime<Utc>) -> MustPurpose<DateTime<Utc>> {
42        MustPurpose::new(
43            Utc.with_ymd_and_hms(dt.year(), dt.month(), dt.day(), 0, 0, 0)
44                .unwrap(),
45        )
46    }
47
48    pub fn end_of_day(&self, dt: DateTime<Utc>) -> MustPurpose<DateTime<Utc>> {
49        MustPurpose::new(self.start_of_day(dt).purpose("internal") + Duration::days(1) - Duration::nanoseconds(1))
50    }
51
52    pub fn days_between(&self, dt1: DateTime<Utc>, dt2: DateTime<Utc>) -> MustPurpose<i64> {
53        let dur = dt2.signed_duration_since(dt1);
54        MustPurpose::new(dur.num_days())
55    }
56
57    pub fn to_timezone(&self, dt: DateTime<Utc>, tz_str: &str) -> Result<MustPurpose<DateTime<Tz>>> {
58        let tz: Tz = tz_str
59            .parse()
60            .map_err(|e| TeaQLToolError::InvalidArgument(format!("{}", e)))?;
61        Ok(MustPurpose::new(dt.with_timezone(&tz)))
62    }
63}
64
65impl Default for TimeTool {
66    fn default() -> Self {
67        Self::new()
68    }
69}