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
}
}