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