ex-cli 1.21.0

Command line tool to find, filter, sort and list files.
Documentation
use crate::error::{MyError, MyResult};
use crate::util::calendar::Calendar;
use chrono::{DateTime, Duration, TimeZone, Utc};
use regex::Regex;
use std::ops::Sub;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum RecentKind {
    None,
    Sec(i64),
    Min(i64),
    Hour(i64),
    Day(i64),
    Week(i64),
    Month(i64),
    Year(i64),
}

impl RecentKind {
    pub fn from_str(value: &str) -> MyResult<Self> {
        let re = Regex::new("^([ymwdhHMS])(\\d+)?$")?;
        match re.captures(value) {
            Some(captures) => {
                let count = captures
                    .get(2)
                    .map(|x| x.as_str())
                    .map(|x| x.parse())
                    .unwrap_or(Ok(1))?;
                let recent = captures
                    .get(1)
                    .map(|x| x.as_str())
                    .map(|x| Self::from_pair(x, count))
                    .unwrap_or(Self::None);
                Ok(recent)
            }
            None => Err(MyError::create_clap("recent", value)),
        }
    }

    fn from_pair(kind: &str, count: i64) -> Self {
        match kind {
            "S" => Self::Sec(count),
            "M" => Self::Min(count),
            "H" | "h" => Self::Hour(count),
            "d" => Self::Day(count),
            "w" => Self::Week(count),
            "m" => Self::Month(count),
            "y" => Self::Year(count),
            _ => Self::None,
        }
    }

    pub fn subtract_from<Tz: TimeZone>(&self, curr_time: &DateTime<Utc>, zone: &Tz) -> Option<DateTime<Utc>> {
        match self {
            Self::None => None,
            Self::Sec(count) => Some(curr_time.sub(Duration::seconds(*count))),
            Self::Min(count) => Some(curr_time.sub(Duration::minutes(*count))),
            Self::Hour(count) => Some(curr_time.sub(Duration::hours(*count))),
            Self::Day(count) => Some(curr_time.sub(Duration::days(*count))),
            Self::Week(count) => Some(curr_time.sub(Duration::weeks(*count))),
            Self::Month(count) => Some(Calendar::from_time(curr_time, zone).subtract_month(*count, zone)),
            Self::Year(count) => Some(Calendar::from_time(curr_time, zone).subtract_year(*count, zone)),
        }
    }

    pub fn from_times<Tz: TimeZone>(
        file_time: &DateTime<Utc>,
        curr_time: &DateTime<Utc>,
        curr_calendar: &Calendar,
        zone: &Tz,
    ) -> Self {
        let delta = curr_time.signed_duration_since(file_time);
        let count = delta.num_days();
        if count > 0 {
            let file_calendar = Calendar::from_time(file_time, zone);
            if let Some(count) = file_calendar.num_years_to(&curr_calendar) {
                return Self::Year(count);
            }
            if let Some(count) = file_calendar.num_months_to(&curr_calendar) {
                return Self::Month(count);
            }
            return Self::Day(count);
        }
        let count = delta.num_hours();
        if count > 0 {
            return Self::Hour(count);
        }
        let count = delta.num_minutes();
        if count > 0 {
            return Self::Min(count);
        }
        let count = delta.num_seconds();
        if count >= 0 {
            return Self::Sec(count);
        }
        Self::None
    }
}

impl Default for RecentKind {
    fn default() -> Self {
        Self::None
    }
}