give up own time module, progress on display command

This commit is contained in:
Abraham Toriz 2021-06-24 00:07:52 -05:00
parent 464925a8b6
commit 4d48386777
No known key found for this signature in database
GPG Key ID: D5B4A746DB5DD42A
7 changed files with 66 additions and 67 deletions

View File

@ -3,10 +3,10 @@ use std::io::Write;
use std::str::FromStr;
use clap::ArgMatches;
use chrono::{DateTime, Utc, Local, TimeZone};
use crate::error;
use crate::database::Database;
use crate::time::Time;
use crate::formatters::Formatter;
use crate::config::Config;
@ -32,8 +32,8 @@ impl FromStr for Sheet {
pub struct Args {
ids: bool,
start: Option<Time>,
end: Option<Time>,
start: Option<DateTime<Utc>>,
end: Option<DateTime<Utc>>,
format: Formatter,
grep: Option<String>,
sheet: Option<Sheet>,
@ -76,6 +76,6 @@ impl<'a> Command<'a> for DisplayCommand {
}
};
args.format.print_formatted(sheets_to_display, out)
args.format.print_formatted(sheets_to_display, out, Utc::now(), Local.offset_from_utc_datetime(&Utc::now().naive_utc()))
}
}

View File

@ -2,16 +2,16 @@ use std::convert::TryFrom;
use std::io::Write;
use clap::ArgMatches;
use chrono::{DateTime, Utc};
use crate::database::Database;
use crate::error;
use crate::time::Time;
use crate::editor;
use crate::commands::Command;
use crate::config::Config;
pub struct Args {
at: Option<Time>,
at: Option<DateTime<Utc>>,
note: Option<String>,
}
@ -36,7 +36,7 @@ impl<'a> Command<'a> for InCommand {
D: Database,
W: Write,
{
let at = args.at.unwrap_or(Time::now());
let at = args.at.unwrap_or(Utc::now());
let note = if let Some(note) = args.note {
note
} else {

View File

@ -1,11 +1,10 @@
use std::path::Path;
use rusqlite::{Connection, ToSql, types::{FromSql, ValueRef, FromSqlResult}};
use chrono::DateTime;
use rusqlite::{Connection, ToSql};
use chrono::{DateTime, Utc};
use crate::error;
use crate::models::{Entry, Meta};
use crate::time::Time;
pub trait Database {
/// This is used to create tables and insert rows
@ -29,7 +28,7 @@ pub trait Database {
self.entry_query("select * from entries order by sheet asc, start asc", &[])
}
fn entry_insert(&mut self, at: Time, note: String) -> error::Result<()> {
fn entry_insert(&mut self, at: DateTime<Utc>, note: String) -> error::Result<()> {
self.execute("", &[])
}
@ -95,9 +94,3 @@ impl Database for SqliteDatabase {
Ok(results)
}
}
impl FromSql for Time {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
Ok(DateTime::column_result(value)?.into())
}
}

View File

@ -3,6 +3,7 @@ use std::io::Write;
use serde::{Serialize, Deserialize};
use itertools::Itertools;
use chrono::{DateTime, Utc, Offset, TimeZone};
use crate::error;
use crate::models::Entry;
@ -15,9 +16,15 @@ pub enum Formatter {
}
impl Formatter {
pub fn print_formatted<W: Write>(&self, entries: Vec<Entry>, out: &mut W) -> error::Result<()> {
/// Prints the given entries to the specified output device.
///
/// the current time is given as the `now` argument and the offset from UTC
/// to the local timezone is given in `offset` to prevent this function from
/// using a secondary effect to retrieve the time and conver dates. This
/// also makes it easier to test.
pub fn print_formatted<W: Write, O: Offset>(&self, entries: Vec<Entry>, out: &mut W, now: DateTime<Utc>, offset: O) -> error::Result<()> {
match &self {
Formatter::Text => self.print_formatted_text(entries, out)?,
Formatter::Text => self.print_formatted_text(entries, out, now, offset)?,
Formatter::Custom(name) => {
}
}
@ -27,11 +34,44 @@ impl Formatter {
/// Print in the default text format. Assume entries are sorted by sheet and
/// then by start
fn print_formatted_text<W: Write>(&self, entries: Vec<Entry>, out: &mut W) -> error::Result<()> {
fn print_formatted_text<W: Write, O: Offset>(&self, entries: Vec<Entry>, out: &mut W, now: DateTime<Utc>, offset: O) -> error::Result<()> {
let grouped_entries = entries.into_iter().group_by(|e| e.sheet.to_string());
// Build a timezone based on the offset given to this function. This
// will later be used to properly group the entries by date in the local
// timezone.
let fixed_offset = offset.fix();
for (key, group) in grouped_entries.into_iter() {
writeln!(out, "Timesheet: {}", key)?;
writeln!(out, " Day Start End Duration Notes")?;
let by_day = group.group_by(|e| fixed_offset.from_utc_datetime(&e.start.naive_utc()).date());
for (date, entries) in by_day.into_iter() {
for (i,entry) in entries.into_iter().enumerate() {
let start = fixed_offset.from_utc_datetime(&entry.start.naive_utc()).time().to_string();
let end = entry.end.map(|t| fixed_offset.from_utc_datetime(&t.naive_utc()).time().to_string()).unwrap_or(" ".into());
let duration = entry.end.unwrap_or(now) - entry.start;
let duration = format!("{}:{:02}:{:02}", duration.num_hours(), duration.num_minutes() % 60, duration.num_seconds() & 60);
if i == 0 {
let date = date.format("%a %b %d, %Y").to_string();
writeln!(
out,
" {date} {start} - {end} {duration} {note}",
date=date, start=start, end=end, duration=duration, note=entry.note,
)?;
} else {
writeln!(
out,
" {start} - {end} {duration} {note}",
start=start, end=end, duration=duration, note=entry.note,
)?;
}
}
}
}
Ok(())
@ -56,9 +96,8 @@ mod tests {
use super::*;
use std::fmt;
use crate::time::Time;
use pretty_assertions::assert_eq;
use chrono::TimeZone;
#[derive(PartialEq, Eq)]
pub struct PrettyString<'a>(pub &'a str);
@ -75,13 +114,16 @@ mod tests {
let formatter = Formatter::Text;
let mut output = Vec::new();
let entries = vec![
Entry::new_sample(1, Time::new(2008, 10, 3, 12, 0, 0), Some(Time::new(2008, 10, 3, 14, 0, 0))),
Entry::new_sample(2, Time::new(2008, 10, 3, 12, 0, 0), Some(Time::new(2008, 10, 3, 14, 0, 0))),
Entry::new_sample(3, Time::new(2008, 10, 5, 16, 0, 0), Some(Time::new(2008, 10, 3, 18, 0, 0))),
Entry::new_sample(4, Time::new(2008, 10, 5, 18, 0, 0), None),
Entry::new_sample(1, Utc.ymd(2008, 10, 3).and_hms(12, 0, 0), Some(Utc.ymd(2008, 10, 3).and_hms(14, 0, 0))),
Entry::new_sample(2, Utc.ymd(2008, 10, 3).and_hms(12, 0, 0), Some(Utc.ymd(2008, 10, 3).and_hms(14, 0, 0))),
Entry::new_sample(3, Utc.ymd(2008, 10, 5).and_hms(16, 0, 0), Some(Utc.ymd(2008, 10, 3).and_hms(18, 0, 0))),
Entry::new_sample(4, Utc.ymd(2008, 10, 5).and_hms(18, 0, 0), None),
];
formatter.print_formatted(entries, &mut output).unwrap();
let now = Utc.ymd(2008, 10, 5).and_hms(20, 0, 0);
let offset = Utc;
formatter.print_formatted(entries, &mut output, now, offset).unwrap();
assert_eq!(PrettyString(&String::from_utf8_lossy(&output)), PrettyString("Timesheet: default
Day Start End Duration Notes

View File

@ -1,4 +1,3 @@
pub mod time;
pub mod commands;
pub mod database;
pub mod config;

View File

@ -1,11 +1,11 @@
use crate::time::Time;
use chrono::{DateTime, Utc};
#[derive(Debug)]
pub struct Entry {
pub id: u64,
pub note: String,
pub start: Time,
pub end: Option<Time>,
pub start: DateTime<Utc>,
pub end: Option<DateTime<Utc>>,
pub sheet: String,
}
@ -18,7 +18,7 @@ pub struct Meta {
impl Entry {
#[cfg(test)]
pub fn new_sample(id: u64, start: Time, end: Option<Time>) -> Entry {
pub fn new_sample(id: u64, start: DateTime<Utc>, end: Option<DateTime<Utc>>) -> Entry {
Entry {
id,
note: format!("entry {}", id),

View File

@ -1,35 +0,0 @@
use std::str::FromStr;
use chrono::{DateTime, Utc, TimeZone};
use crate::error;
/// A time in UTC.
///
/// Just a wrapper around Chrono::Utc
#[derive(Debug)]
pub struct Time(DateTime<Utc>);
impl Time {
pub fn now() -> Time {
Time(Utc::now())
}
pub fn new(y: i32, mo: u32, d: u32, h: u32, mi: u32, s: u32) -> Time {
Time(Utc.ymd(y, mo, d).and_hms(h, mi, s))
}
}
impl From<DateTime<Utc>> for Time {
fn from(dt: DateTime<Utc>) -> Time {
Time(dt)
}
}
impl FromStr for Time {
type Err = error::Error;
fn from_str(s: &str) -> error::Result<Time> {
unimplemented!()
}
}