give up own time module, progress on display command
This commit is contained in:
parent
464925a8b6
commit
4d48386777
|
@ -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()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
pub mod time;
|
||||
pub mod commands;
|
||||
pub mod database;
|
||||
pub mod config;
|
||||
|
|
|
@ -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),
|
||||
|
|
35
src/time.rs
35
src/time.rs
|
@ -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!()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue