87 lines
3.0 KiB
Rust
87 lines
3.0 KiB
Rust
use std::io::Write;
|
|
|
|
use chrono::{DateTime, Utc, Local, LocalResult, TimeZone};
|
|
use ansi_term::Color::Yellow;
|
|
|
|
use crate::error::{Error::*, Result};
|
|
use crate::models::Entry;
|
|
use crate::database::{Database, DBVersion};
|
|
|
|
/// Treat t as if it wasnt actually in Utc but in the local timezone and return
|
|
/// the actual Utc time.
|
|
///
|
|
/// Used to convert times from the old database version.
|
|
fn local_to_utc(t: DateTime<Utc>) -> Result<DateTime<Utc>> {
|
|
let local_time = match Local.from_local_datetime(&t.naive_utc()) {
|
|
LocalResult::None => return Err(NoneLocalTime(t.naive_utc().to_string())),
|
|
LocalResult::Single(t) => t,
|
|
LocalResult::Ambiguous(t1, t2) => return Err(AmbiguousLocalTime {
|
|
orig: t.naive_utc().to_string(),
|
|
t1: t1.naive_local(),
|
|
t2: t2.naive_local(),
|
|
}),
|
|
};
|
|
|
|
Ok(Utc.from_utc_datetime(&local_time.naive_utc()))
|
|
}
|
|
|
|
/// takes an otherwise perfectly good timestamp in Utc and turns it into the
|
|
/// local timezone, but using the same DateTime<Utc> type.
|
|
///
|
|
/// Used to insert times into the old database format.
|
|
fn utc_to_local(t: DateTime<Utc>) -> DateTime<Utc> {
|
|
Utc.from_utc_datetime(&t.with_timezone(&Local).naive_local())
|
|
}
|
|
|
|
/// Maps an entire vector of entries from the old database format to the new,
|
|
/// converting their timestamps from the local timezone to Utc.
|
|
fn local_to_utc_vec(entries: Vec<Entry>) -> Result<Vec<Entry>> {
|
|
entries
|
|
.into_iter()
|
|
.map(|e| {
|
|
Ok(Entry {
|
|
start: local_to_utc(e.start)?,
|
|
end: e.end.map(local_to_utc).transpose()?,
|
|
..e
|
|
})
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
/// the logic used by many subcommands that transform entries from the old
|
|
/// format to the new. Used in conjunction with warn_if_needed.
|
|
pub fn entries_or_warning<D: Database>(entries: Vec<Entry>, db: &D) -> Result<(Vec<Entry>, bool)> {
|
|
if let DBVersion::Timetrap = db.version()? {
|
|
// this indicates that times in the database are specified in the
|
|
// local time and need to be converted to utc before displaying
|
|
|
|
Ok((local_to_utc_vec(entries)?, true))
|
|
} else {
|
|
Ok((entries, false))
|
|
}
|
|
}
|
|
|
|
/// Wrapper around utc_to_local that also returns a flag in case a warning is
|
|
/// needed
|
|
pub fn time_or_warning<D: Database>(time: DateTime<Utc>, db: &D) -> Result<(DateTime<Utc>, bool)> {
|
|
if let DBVersion::Timetrap = db.version()? {
|
|
Ok((utc_to_local(time), true))
|
|
} else {
|
|
Ok((time, false))
|
|
}
|
|
}
|
|
|
|
/// emits the appropiate warning if the old database format was detected.
|
|
pub fn warn_if_needed<E: Write>(err: &mut E, needs_warning: bool) -> Result<()> {
|
|
if needs_warning && std::env::var_os("TIEMPO_SUPRESS_TIMETRAP_WARNING").is_none() {
|
|
writeln!(
|
|
err,
|
|
"{} You are using the old timetrap format, it is advised that \
|
|
you update your database using t migrate",
|
|
Yellow.bold().paint("[WARNING]"),
|
|
).map_err(IOError)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|