use std::{collections::HashMap, convert::TryFrom};
use chrono::{Date, DateTime, Duration, Local, Utc};
#[derive(Debug, Clone)]
pub struct Elapsed<'a> {
datetime_context: DateTime<Local>,
datetime: DateTime<Local>,
date: Date<Local>,
duration: Duration,
passed: bool,
cache: HashMap<TimeFrame, (&'a str, usize)>, }
pub type DueDateTime<'a> = Elapsed<'a>;
impl Elapsed<'_> {
pub fn new(datetime: DateTime<Local>) -> Self {
let datetime_context = Local::now();
Self {
datetime_context,
datetime,
date: datetime.date(),
duration: datetime.signed_duration_since(datetime_context),
passed: datetime.le(&datetime_context),
cache: HashMap::new(),
}
}
pub fn new_from_date(date: Date<Local>) -> Self {
let datetime = date.and_hms(0, 0, 0);
let datetime_context = Local::now();
Self {
datetime_context,
datetime,
date,
duration: datetime.signed_duration_since(datetime_context),
passed: datetime.le(&datetime_context),
cache: HashMap::new(),
}
}
pub fn new_then_localize(datetime: DateTime<Utc>) -> Self {
let datetime_context = Local::now();
let datetime = datetime.with_timezone(&Local);
Self {
datetime_context,
datetime,
date: datetime.date(),
duration: datetime.signed_duration_since(datetime_context),
passed: datetime.le(&datetime_context),
cache: HashMap::new(),
}
}
pub fn new_from_date_then_localize(date: Date<Utc>) -> Self {
let datetime = date.and_hms(0, 0, 0).with_timezone(&Local);
let datetime_context = Local::now();
Self {
datetime_context,
datetime,
date: datetime.date(),
duration: datetime.signed_duration_since(datetime_context),
passed: datetime.le(&datetime_context),
cache: HashMap::new(),
}
}
pub fn new_with_context(datetime: DateTime<Local>, context: DateTime<Local>) -> Self {
Self {
datetime_context: context,
datetime,
date: datetime.date(),
duration: datetime.signed_duration_since(context),
passed: datetime.le(&context),
cache: HashMap::new(),
}
}
pub fn new_from_date_with_context(date: Date<Local>, context: Date<Local>) -> Self {
let datetime = date.and_hms(0, 0, 0);
let datetime_context = context.and_hms(0, 0, 0);
Self {
datetime_context,
datetime,
date,
duration: datetime.signed_duration_since(datetime_context),
passed: datetime.le(&datetime_context),
cache: HashMap::new(),
}
}
pub fn set_datetime_context(&mut self, datetime_context: DateTime<Local>) -> &mut Self {
self.datetime_context = datetime_context;
self.duration = self.datetime.signed_duration_since(datetime_context);
self.passed = self.datetime.le(&self.datetime_context);
self
}
pub fn set_datetime(&mut self, datetime: DateTime<Local>) -> &mut Self {
self.datetime = datetime;
self.date = datetime.date();
self.duration = datetime.signed_duration_since(self.datetime_context);
self.passed = datetime.le(&self.datetime_context);
self
}
pub fn set_date(&mut self, date: Date<Local>) {
self.date = date;
self.datetime = date.and_hms(0, 0, 0);
self.duration = self.datetime.signed_duration_since(self.datetime_context);
self.passed = self.datetime.le(&self.datetime_context);
}
}
impl From<DateTime<Local>> for Elapsed<'_> {
fn from(datetime: DateTime<Local>) -> Self {
Self::new(datetime)
}
}
impl From<Date<Local>> for Elapsed<'_> {
fn from(date: Date<Local>) -> Self {
Self::new_from_date(date)
}
}
impl From<DateTime<Utc>> for Elapsed<'_> {
fn from(datetime: DateTime<Utc>) -> Self {
Self::new_then_localize(datetime)
}
}
impl From<Date<Utc>> for Elapsed<'_> {
fn from(date: Date<Utc>) -> Self {
Self::new_from_date_then_localize(date)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
enum TimeFrame {
MilliSecond,
Second,
Minute,
Hour,
Day,
Week,
Month,
Year,
}
impl From<TimeFrame> for String {
fn from(tf: TimeFrame) -> Self {
match tf {
TimeFrame::MilliSecond => String::from("millisecond(s)"),
TimeFrame::Second => String::from("second(s)"),
TimeFrame::Minute => String::from("minute(s)"),
TimeFrame::Hour => String::from("hour(s)"),
TimeFrame::Day => String::from("day(s)"),
TimeFrame::Week => String::from("week(s)"),
TimeFrame::Month => String::from("month(s)"),
TimeFrame::Year => String::from("year(s)"),
}
}
}
impl TryFrom<&str> for TimeFrame {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value.to_lowercase().trim() {
"millisecond" | "ms" => Ok(Self::MilliSecond),
"second" | "sec" | "s" => Ok(Self::Second),
"minute" | "min" => Ok(Self::Minute),
"hour" | "hr" | "h" => Ok(Self::Hour),
"day" | "d" => Ok(Self::Day),
"week" | "wk" | "w" => Ok(Self::Week),
"month" | "mon" => Ok(Self::Month),
"year" | "yr" | "y" => Ok(Self::Year),
_ => Err("Invalid or ambiguous string for `elapsed::TimeFrame`"),
}
}
}
impl From<TimeFrame> for char {
fn from(tf: TimeFrame) -> Self {
match tf {
TimeFrame::MilliSecond => 'm',
TimeFrame::Second => 's',
TimeFrame::Minute => 'm',
TimeFrame::Hour => 'h',
TimeFrame::Day => 'd',
TimeFrame::Week => 'w',
TimeFrame::Month => 'm',
TimeFrame::Year => 'y',
}
}
}
impl TryFrom<char> for TimeFrame {
type Error = &'static str;
fn try_from(value: char) -> Result<Self, Self::Error> {
match value.to_ascii_lowercase() {
's' => Ok(Self::Second),
'h' => Ok(Self::Hour),
'd' => Ok(Self::Day),
'w' => Ok(Self::Week),
'y' => Ok(Self::Year),
_ => Err("Invalid or ambiguous char for `elapsed::TimeFrame`"),
}
}
}
pub trait Abbreviate {
fn abbrev(&self) -> &str;
fn abbrev_short(&self) -> &str;
}
impl Abbreviate for TimeFrame {
fn abbrev(&self) -> &str {
match self {
TimeFrame::MilliSecond => "ms",
TimeFrame::Second => "sec",
TimeFrame::Minute => "min",
TimeFrame::Hour => "hr",
TimeFrame::Day => "d",
TimeFrame::Week => "w",
TimeFrame::Month => "m",
TimeFrame::Year => "y",
}
}
fn abbrev_short(&self) -> &str {
match self {
TimeFrame::MilliSecond => "ms",
TimeFrame::Second => "s",
TimeFrame::Minute => "min",
TimeFrame::Hour => "h",
TimeFrame::Day => "d",
TimeFrame::Week => "w",
TimeFrame::Month => "m",
TimeFrame::Year => "y",
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}