Add comments and support for wrapping to a new day
This commit is contained in:
parent
6137e6c046
commit
283876ebda
3 changed files with 39 additions and 12 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -360,7 +360,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-track"
|
name = "time-track"
|
||||||
version = "0.3.5"
|
version = "0.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"atty",
|
"atty",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "time-track"
|
name = "time-track"
|
||||||
version = "0.3.5"
|
version = "0.4.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
|
||||||
47
src/main.rs
47
src/main.rs
|
|
@ -1,9 +1,9 @@
|
||||||
use std::io::{stdin, BufRead};
|
use std::io::{stdin, BufRead};
|
||||||
|
|
||||||
use chrono::{NaiveTime, Duration, Local};
|
use chrono::{NaiveTime, Duration, Local, NaiveDateTime};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use atty::Stream;
|
use atty::Stream;
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
mod modes;
|
mod modes;
|
||||||
use modes::Modes;
|
use modes::Modes;
|
||||||
|
|
@ -16,11 +16,23 @@ struct Args {
|
||||||
#[clap(value_enum, default_value_t = Modes::default())]
|
#[clap(value_enum, default_value_t = Modes::default())]
|
||||||
mode: Modes,
|
mode: Modes,
|
||||||
}
|
}
|
||||||
fn parse_time(time_str: &str) -> Result<NaiveTime> {
|
|
||||||
let time = NaiveTime::parse_from_str(time_str, "%H:%M")?;
|
fn epoch() -> NaiveTime {
|
||||||
Ok(time)
|
NaiveTime::from_hms_opt(0, 0, 0).expect("0, 0, 0 to be valid arguments to from_hms_opt")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given an arbitrary string, attempt to parse it as a naive time in the format HH:mm
|
||||||
|
fn parse_time(time_str: &str) -> Result<NaiveDateTime> {
|
||||||
|
let time = NaiveTime::parse_from_str(time_str, "%H:%M")?;
|
||||||
|
let naive_date = NaiveDateTime::from_timestamp_millis(
|
||||||
|
time.signed_duration_since(epoch()).num_milliseconds(),
|
||||||
|
).ok_or(anyhow!("Should be able to make a datetime"))?;
|
||||||
|
Ok(naive_date)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default way of calculating time. Time values are given one per line and subsequent pairs of
|
||||||
|
/// lines are considered time spans. If an odd number of spans is given, then the final time value
|
||||||
|
/// is ignored.
|
||||||
fn all_at_once(is_terminal: bool) -> Result<Vec<Duration>> {
|
fn all_at_once(is_terminal: bool) -> Result<Vec<Duration>> {
|
||||||
if is_terminal {
|
if is_terminal {
|
||||||
println!("Enter simple times one per line. Send an EOF character to sum all time spans");
|
println!("Enter simple times one per line. Send an EOF character to sum all time spans");
|
||||||
|
|
@ -33,8 +45,19 @@ fn all_at_once(is_terminal: bool) -> Result<Vec<Duration>> {
|
||||||
if let Some(previous) = &seen {
|
if let Some(previous) = &seen {
|
||||||
let first = parse_time(previous)?;
|
let first = parse_time(previous)?;
|
||||||
let mut second = parse_time(&cleaned)?;
|
let mut second = parse_time(&cleaned)?;
|
||||||
if second < first {
|
|
||||||
|
// The following logic attempts to handle wrapping from AM -> PM and also from PM ->
|
||||||
|
// AM but cannot handle multiple days in a single span
|
||||||
|
if (second < first) && first.time().signed_duration_since(epoch()).num_hours() < 12 {
|
||||||
|
// Assuming wrapped to PM
|
||||||
|
// first = 8:00
|
||||||
|
// second: 1:00
|
||||||
second = second + Duration::hours(12);
|
second = second + Duration::hours(12);
|
||||||
|
} else if second < first {
|
||||||
|
// Wrapped to a new day because first was after noon.
|
||||||
|
// first = 14:40
|
||||||
|
// second = 1:30
|
||||||
|
second = second + Duration::hours(24)
|
||||||
}
|
}
|
||||||
durations.push(second - first);
|
durations.push(second - first);
|
||||||
seen = None;
|
seen = None;
|
||||||
|
|
@ -48,6 +71,8 @@ fn all_at_once(is_terminal: bool) -> Result<Vec<Duration>> {
|
||||||
return Ok(durations);
|
return Ok(durations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A "live" time tracker. Each time the user presses enter a new span is started or an existing
|
||||||
|
/// span is closed. The user may end the tracking at any time by sending an EOF command.
|
||||||
fn live_spans() -> Result<Vec<Duration>> {
|
fn live_spans() -> Result<Vec<Duration>> {
|
||||||
println!("Tracking Spans Live. Press ENTER to start a span\n");
|
println!("Tracking Spans Live. Press ENTER to start a span\n");
|
||||||
let mut durations = vec![];
|
let mut durations = vec![];
|
||||||
|
|
@ -82,7 +107,9 @@ fn live_spans() -> Result<Vec<Duration>> {
|
||||||
return Ok(durations);
|
return Ok(durations);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_prediction() -> Result<NaiveTime> {
|
/// Predict when the given amount of work has completed based on when the user started working and
|
||||||
|
/// how long they expect to be on break total.
|
||||||
|
fn get_prediction(hours: i64) -> Result<NaiveTime> {
|
||||||
println!("Calculating an end time prediction...\nWhen did you start?\n");
|
println!("Calculating an end time prediction...\nWhen did you start?\n");
|
||||||
let mut start_time = String::new();
|
let mut start_time = String::new();
|
||||||
let _ = stdin().read_line(&mut start_time);
|
let _ = stdin().read_line(&mut start_time);
|
||||||
|
|
@ -92,8 +119,8 @@ fn get_prediction() -> Result<NaiveTime> {
|
||||||
let mut break_time = String::new();
|
let mut break_time = String::new();
|
||||||
let _ = stdin().read_line(&mut break_time);
|
let _ = stdin().read_line(&mut break_time);
|
||||||
let break_duration = break_time.trim().parse::<i64>()?;
|
let break_duration = break_time.trim().parse::<i64>()?;
|
||||||
let work_time = Duration::hours(8) + Duration::minutes(break_duration);
|
let work_time = Duration::hours(hours) + Duration::minutes(break_duration);
|
||||||
return Ok(start + work_time);
|
return Ok(start.time() + work_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
@ -105,7 +132,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.mode == Modes::Prediction {
|
if args.mode == Modes::Prediction {
|
||||||
if let Ok(prediction) = get_prediction() {
|
if let Ok(prediction) = get_prediction(8 /* hours */) {
|
||||||
println!("Your work will end at {}", prediction);
|
println!("Your work will end at {}", prediction);
|
||||||
} else {
|
} else {
|
||||||
println!("Something went wrong...");
|
println!("Something went wrong...");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue