Skip to main content

ex_cli/cli/
recent.rs

1use crate::error::{MyError, MyResult};
2use crate::util::calendar::Calendar;
3use chrono::{DateTime, Duration, TimeZone, Utc};
4use regex::Regex;
5use std::ops::Sub;
6
7#[derive(Clone, Copy, Debug, PartialEq)]
8pub enum RecentKind {
9    None,
10    Sec(i64),
11    Min(i64),
12    Hour(i64),
13    Day(i64),
14    Week(i64),
15    Month(i64),
16    Year(i64),
17}
18
19impl RecentKind {
20    pub fn from_str(value: &str) -> MyResult<Self> {
21        let re = Regex::new("^([ymwdhHMS])(\\d+)?$")?;
22        match re.captures(value) {
23            Some(captures) => {
24                let count = captures
25                    .get(2)
26                    .map(|x| x.as_str())
27                    .map(|x| x.parse())
28                    .unwrap_or(Ok(1))?;
29                let recent = captures
30                    .get(1)
31                    .map(|x| x.as_str())
32                    .map(|x| Self::from_pair(x, count))
33                    .unwrap_or(Self::None);
34                Ok(recent)
35            }
36            None => Err(MyError::create_clap("recent", value)),
37        }
38    }
39
40    fn from_pair(kind: &str, count: i64) -> Self {
41        match kind {
42            "S" => Self::Sec(count),
43            "M" => Self::Min(count),
44            "H" | "h" => Self::Hour(count),
45            "d" => Self::Day(count),
46            "w" => Self::Week(count),
47            "m" => Self::Month(count),
48            "y" => Self::Year(count),
49            _ => Self::None,
50        }
51    }
52
53    pub fn subtract_from<Tz: TimeZone>(&self, curr_time: &DateTime<Utc>, zone: &Tz) -> Option<DateTime<Utc>> {
54        match self {
55            Self::None => None,
56            Self::Sec(count) => Some(curr_time.sub(Duration::seconds(*count))),
57            Self::Min(count) => Some(curr_time.sub(Duration::minutes(*count))),
58            Self::Hour(count) => Some(curr_time.sub(Duration::hours(*count))),
59            Self::Day(count) => Some(curr_time.sub(Duration::days(*count))),
60            Self::Week(count) => Some(curr_time.sub(Duration::weeks(*count))),
61            Self::Month(count) => Some(Calendar::from_time(curr_time, zone).subtract_month(*count, zone)),
62            Self::Year(count) => Some(Calendar::from_time(curr_time, zone).subtract_year(*count, zone)),
63        }
64    }
65
66    pub fn from_times<Tz: TimeZone>(
67        file_time: &DateTime<Utc>,
68        curr_time: &DateTime<Utc>,
69        curr_calendar: &Calendar,
70        zone: &Tz,
71    ) -> Self {
72        let delta = curr_time.signed_duration_since(file_time);
73        let count = delta.num_days();
74        if count > 0 {
75            let file_calendar = Calendar::from_time(file_time, zone);
76            if let Some(count) = file_calendar.num_years_to(&curr_calendar) {
77                return Self::Year(count);
78            }
79            if let Some(count) = file_calendar.num_months_to(&curr_calendar) {
80                return Self::Month(count);
81            }
82            return Self::Day(count);
83        }
84        let count = delta.num_hours();
85        if count > 0 {
86            return Self::Hour(count);
87        }
88        let count = delta.num_minutes();
89        if count > 0 {
90            return Self::Min(count);
91        }
92        let count = delta.num_seconds();
93        if count >= 0 {
94            return Self::Sec(count);
95        }
96        Self::None
97    }
98}
99
100impl Default for RecentKind {
101    fn default() -> Self {
102        Self::None
103    }
104}