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}