Skip to content

Commit

Permalink
feat: multi threading with chrono
Browse files Browse the repository at this point in the history
  • Loading branch information
azzamsa committed Jul 22, 2023
1 parent df53b9d commit 5a94c01
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 139 deletions.
296 changes: 243 additions & 53 deletions Cargo.lock

Large diffs are not rendered by default.

14 changes: 6 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,15 @@ lto = true
panic = 'abort'

[dependencies]
anyhow = "1.0"
chrono = "0.4.26"
owo-colors = "3"
thiserror = "1.0"

[dependencies.clap]
version = "4.0"
features = ["suggestions", "color", "cargo", "derive"]
# cli
clap = { version = "4.0", features = ["suggestions", "color", "cargo", "derive"] }

[dependencies.time]
version = "0.3.17"
features = ["macros", "formatting", "local-offset"]
# error
anyhow = "1.0"
thiserror = "1.0"

[dev-dependencies]
assert_cmd = "2.0"
Expand Down
13 changes: 2 additions & 11 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,7 @@ use thiserror::Error;
pub enum Error {
#[error("{0}")]
InvalidArgument(String),
}

impl std::convert::From<time::error::IndeterminateOffset> for Error {
fn from(err: time::error::IndeterminateOffset) -> Self {
Self::InvalidArgument(err.to_string())
}
}

impl std::convert::From<time::error::ComponentRange> for Error {
fn from(err: time::error::ComponentRange) -> Self {
Self::InvalidArgument(err.to_string())
}
#[error("No such time")]
InvalidTime,
}
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@ pub mod cli;
pub mod error;
pub mod output;
pub mod progress;

pub use error::Error;

// Use internal type. Chrono API changes very often
pub type Date = chrono::NaiveDate;
pub type DateTime = chrono::NaiveDateTime;
16 changes: 10 additions & 6 deletions src/progress/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,30 @@ pub use month::month;
pub mod week;
pub use week::week;

use time::{Date, OffsetDateTime};
use chrono::{Local, NaiveDate};

use crate::error::Error;
use crate::{error::Error, Date};

// Calculate the ratio of time progress
fn compute(current: Date, start: Date, end: Date) -> Result<f64, Error> {
let whole_diff = end - start;
// 86_400 is total second in a day (24 * 3600)
let total_seconds_in_day = 84_000;
let whole_diff_in_seconds =
whole_diff.whole_days() * total_seconds_in_day + whole_diff.whole_seconds();
whole_diff.num_days() * total_seconds_in_day + whole_diff.num_seconds();

let current_diff = current - start;
let current_diff_in_seconds =
current_diff.whole_days() * total_seconds_in_day + current_diff.whole_seconds();
current_diff.num_days() * total_seconds_in_day + current_diff.num_seconds();
// progress_ratio
let ratio = current_diff_in_seconds as f64 / whole_diff_in_seconds as f64;
Ok(ratio)
}

fn today() -> Result<Date, Error> {
Ok(OffsetDateTime::now_local()?.date())
pub fn today() -> Date {
Local::now().date_naive()
}

pub fn date(year: i32, month: u32, day: u32) -> Result<Date, crate::Error> {
NaiveDate::from_ymd_opt(year, month, day).ok_or(crate::Error::InvalidTime)
}
51 changes: 25 additions & 26 deletions src/progress/month.rs
Original file line number Diff line number Diff line change
@@ -1,65 +1,64 @@
use time::{Date, Month};
use chrono::Datelike;

use super::{compute, today};
use crate::error::Error;
use crate::{error::Error, progress::date, Date};

pub fn month() -> Result<f64, Error> {
month_ratio(today()?)
month_ratio(today())
}

fn month_ratio(today: Date) -> Result<f64, Error> {
let start = Date::from_calendar_date(today.year(), today.month(), 1)?;
let start = date(today.year(), today.month(), 1)?;
let end_date = end_date_in_current_month(today)?;
let end = Date::from_calendar_date(today.year(), today.month(), end_date as u8)?;
let end = date(today.year(), today.month(), end_date as u32)?;
compute(today, start, end)
}

/// Count the end date in current month
fn end_date_in_current_month(today: Date) -> Result<i64, Error> {
let (year, month) = (today.year(), today.month());
let start = Date::from_calendar_date(year, month, 1)?;
let start = date(year, month, 1)?;

let end_year = if month == Month::December {
year + 1
} else {
year
};
let end_month = if month == Month::December {
Month::January
// `12` is December
let end_year = if month == 12 { year + 1 } else { year };

// `12` is December
let end_month = if month == 12 {
1 // January
} else {
month.next()
month + 1
};
let end = Date::from_calendar_date(end_year, end_month, 1)?;
let end = date(end_year, end_month, 1)?;

Ok((end - start).whole_days())
Ok((end - start).num_days())
}

#[cfg(test)]
mod tests {
use super::*;
use crate::progress::date;
use anyhow::Result;
use time::macros::date;

#[test]
fn month_should_be_0() -> Result<()> {
// first day of the month
let current = date!(2021 - 1 - 1);
let current = date(2021, 1, 1)?;
let ratio = month_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

assert_eq!(ratio, 0.0);
assert_eq!(ratio_int, 0);

// first day of the month
let current = date!(2021 - 2 - 1);
let current = date(2021, 2, 1)?;
let ratio = month_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

assert_eq!(ratio, 0.0);
assert_eq!(ratio_int, 0);

// first day of the month
let current = date!(2020 - 1 - 1);
let current = date(2020, 1, 1)?;
let ratio = month_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

Expand All @@ -71,15 +70,15 @@ mod tests {
#[test]
fn month_should_be_50() -> Result<()> {
// middle day of the month
let current = date!(2021 - 1 - 16);
let current = date(2021, 1, 16)?;
let ratio = month_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

assert_eq!(ratio, 0.5);
assert_eq!(ratio_int, 50);

// middle day of the month
let current = date!(2021 - 2 - 15);
let current = date(2021, 2, 15)?;
let ratio = month_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

Expand All @@ -88,7 +87,7 @@ mod tests {
assert_eq!(ratio_int, 51);

// middle of the month
let current = date!(2021 - 3 - 16);
let current = date(2021, 3, 16)?;
let ratio = month_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

Expand All @@ -100,23 +99,23 @@ mod tests {
#[test]
fn month_should_be_100() -> Result<()> {
// last day of the month
let current = date!(2021 - 1 - 31);
let current = date(2021, 1, 31)?;
let ratio = month_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

assert_eq!(ratio, 1.0);
assert_eq!(ratio_int, 100);

// last day of the month
let current = date!(2021 - 2 - 28);
let current = date(2021, 2, 28)?;
let ratio = month_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

assert_eq!(ratio, 1.0);
assert_eq!(ratio_int, 100);

// last day of the month
let current = date!(2020 - 1 - 31);
let current = date(2020, 1, 31)?;
let ratio = month_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

Expand Down
27 changes: 14 additions & 13 deletions src/progress/week.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,43 @@
use time::{Date, Duration};
use crate::Date;
use chrono::{Datelike, Duration};

use super::{compute, today};
use crate::error::Error;

pub fn week() -> Result<f64, Error> {
week_ratio(today()?)
week_ratio(today())
}

fn week_ratio(current: Date) -> Result<f64, Error> {
let start = current - Duration::days(current.weekday().number_days_from_monday().into());
let start = current - Duration::days(current.weekday().num_days_from_monday().into());
let end = start + Duration::days(6);
compute(current, start, end)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::progress::date;
use anyhow::Result;
use time::macros::date;

#[test]
fn week_should_be_0() -> Result<()> {
// first day of the week
let current = date!(2021 - 1 - 4);
let current = date(2021, 1, 4)?;
let ratio = week_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;
assert_eq!(ratio, 0.0);
assert_eq!(ratio_int, 0);

// first day of the week
let current = date!(2021 - 1 - 11);
let current = date(2021, 1, 11)?;
let ratio = week_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;
assert_eq!(ratio, 0.0);
assert_eq!(ratio_int, 0);

// first day of the week
let current = date!(2020 - 1 - 6);
let current = date(2020, 1, 6)?;
let ratio = week_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;
assert_eq!(ratio, 0.0);
Expand All @@ -47,23 +48,23 @@ mod tests {
#[test]
fn week_should_be_50() -> Result<()> {
// middle day of the week
let current = date!(2021 - 1 - 7);
let current = date(2021, 1, 7)?;
let ratio = week_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

assert_eq!(ratio, 0.5);
assert_eq!(ratio_int, 50);

// middle day of the week
let current = date!(2021 - 1 - 14);
let current = date(2021, 1, 14)?;
let ratio = week_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

assert_eq!(ratio, 0.5);
assert_eq!(ratio_int, 50);

// middle day of the week
let current = date!(2020 - 1 - 9);
let current = date(2020, 1, 9)?;
let ratio = week_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

Expand All @@ -75,23 +76,23 @@ mod tests {
#[test]
fn week_should_be_100() -> Result<()> {
// last day of the week
let current = date!(2021 - 1 - 10);
let current = date(2021, 1, 10)?;
let ratio = week_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

assert_eq!(ratio, 1.0);
assert_eq!(ratio_int, 100);

// last day of the week
let current = date!(2021 - 1 - 17);
let current = date(2021, 1, 17)?;
let ratio = week_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

assert_eq!(ratio, 1.0);
assert_eq!(ratio_int, 100);

// last day of the week
let current = date!(2020 - 1 - 12);
let current = date(2020, 1, 12)?;
let ratio = week_ratio(current)?;
let ratio_int = (ratio * 100.0) as i32;

Expand Down

0 comments on commit 5a94c01

Please sign in to comment.