diff options
author | Daniel <kingdread@gmx.de> | 2020-05-01 12:51:06 +0200 |
---|---|---|
committer | Daniel <kingdread@gmx.de> | 2020-05-01 12:51:06 +0200 |
commit | cb757209d438afe23b5bdbfa5f62d00b195ad367 (patch) | |
tree | 3795c8241933c360bb9be099ede2e0d6e0cb85ca | |
parent | 9d5b728ce507334ad3916e2628dab1e0d82f5882 (diff) | |
download | raidgrep-cb757209d438afe23b5bdbfa5f62d00b195ad367.tar.gz raidgrep-cb757209d438afe23b5bdbfa5f62d00b195ad367.tar.bz2 raidgrep-cb757209d438afe23b5bdbfa5f62d00b195ad367.zip |
fix timestamp handling
As it turns out, the "local timestamp" as advertised by arcdps is a bit
misleading, because the timestamp is still in UTC. The "local" refers to
the fact that it can lag behind the server timestamp a bit (but usually
they seem to be within +-1 of each other), not that the timestamp is in
the local timezone.
This makes date handling a bit harder for raidgrep, but thanks to
chrono, not by much. The idea is that we simply deal with Utc pretty
much everywhere, except at the user boundary. This means that
1. Input timestamps for -before and -after are converted to Utc right
after input
2. When outputting, we convert to a local timestamp first
This makes the output consistent with the filenames now (and the "wall
time" that the player saw).
-rw-r--r-- | src/fexpr/grammar.lalrpop | 14 | ||||
-rw-r--r-- | src/filters/log.rs | 12 | ||||
-rw-r--r-- | src/main.rs | 6 | ||||
-rw-r--r-- | src/output/formats.rs | 6 |
4 files changed, 21 insertions, 17 deletions
diff --git a/src/fexpr/grammar.lalrpop b/src/fexpr/grammar.lalrpop index f193a90..8674b84 100644 --- a/src/fexpr/grammar.lalrpop +++ b/src/fexpr/grammar.lalrpop @@ -10,7 +10,7 @@ use evtclib::Boss; use std::collections::HashSet; use lalrpop_util::ParseError; -use chrono::NaiveDateTime; +use chrono::{DateTime, Local, TimeZone, Utc}; use regex::Regex; grammar; @@ -134,23 +134,25 @@ Boss: Boss = { }), } -Date: NaiveDateTime = { - <l:@L> <d:datetime> =>? NaiveDateTime::parse_from_str(d, "%Y-%m-%d %H:%M:%S") +Date: DateTime<Utc> = { + <l:@L> <d:datetime> =>? Local.datetime_from_str(d, "%Y-%m-%d %H:%M:%S") .map_err(|error| ParseError::User { error: FError { location: l, data: d.into(), kind: error.into(), } - }), - <l:@L> <d:date> =>? NaiveDateTime::parse_from_str(&format!("{} 00:00:00", d), "%Y-%m-%d %H:%M:%S") + }) + .map(|d| d.with_timezone(&Utc)), + <l:@L> <d:date> =>? Local.datetime_from_str(&format!("{} 00:00:00", d), "%Y-%m-%d %H:%M:%S") .map_err(|error| ParseError::User { error: FError { location: l, data: d.into(), kind: error.into(), } - }), + }) + .map(|d| d.with_timezone(&Utc)), } Comma<T>: HashSet<T> = { diff --git a/src/filters/log.rs b/src/filters/log.rs index 59e6b8c..2d2fc37 100644 --- a/src/filters/log.rs +++ b/src/filters/log.rs @@ -12,7 +12,7 @@ use std::collections::HashSet; use evtclib::raw::parser::PartialEvtc; use evtclib::Boss; -use chrono::{Datelike, NaiveDateTime}; +use chrono::{DateTime, Datelike, Utc}; use num_traits::FromPrimitive as _; /// Filter trait used for filters that operate on complete logs. @@ -39,7 +39,6 @@ pub fn boss(bosses: HashSet<Boss>) -> Box<dyn LogFilter> { Box::new(BossFilter(bosses)) } - #[derive(Debug, Clone)] struct OutcomeFilter(HashSet<FightOutcome>); @@ -88,9 +87,8 @@ pub fn weekday(weekdays: HashSet<Weekday>) -> Box<dyn LogFilter> { Box::new(WeekdayFilter(weekdays)) } - #[derive(Debug, Clone)] -struct TimeFilter(Option<NaiveDateTime>, Option<NaiveDateTime>); +struct TimeFilter(Option<DateTime<Utc>>, Option<DateTime<Utc>>); impl Filter<PartialEvtc, LogResult> for TimeFilter { fn filter(&self, log: &LogResult) -> bool { @@ -111,20 +109,20 @@ impl Filter<PartialEvtc, LogResult> for TimeFilter { /// /// If a bound is not given, -Infinity is assumed for the lower bound, and Infinity for the upper /// bound. -pub fn time(lower: Option<NaiveDateTime>, upper: Option<NaiveDateTime>) -> Box<dyn LogFilter> { +pub fn time(lower: Option<DateTime<Utc>>, upper: Option<DateTime<Utc>>) -> Box<dyn LogFilter> { Box::new(TimeFilter(lower, upper)) } /// A `LogFilter` that only accepts logs after the given date. /// /// Also see [`time`][time] and [`before`][before]. -pub fn after(when: NaiveDateTime) -> Box<dyn LogFilter> { +pub fn after(when: DateTime<Utc>) -> Box<dyn LogFilter> { time(Some(when), None) } /// A `LogFilter` that only accepts logs before the given date. /// /// Also see [`time`][time] and [`after`][after]. -pub fn before(when: NaiveDateTime) -> Box<dyn LogFilter> { +pub fn before(when: DateTime<Utc>) -> Box<dyn LogFilter> { time(None, Some(when)) } diff --git a/src/main.rs b/src/main.rs index 712da94..b2b578d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; use std::str::FromStr; use anyhow::{anyhow, Error, Result}; -use chrono::{NaiveDateTime, Weekday}; +use chrono::{DateTime, TimeZone, Utc, Weekday}; use colored::Colorize; use itertools::Itertools; use log::debug; @@ -122,7 +122,7 @@ pub struct LogResult { /// The path to the log file. log_file: PathBuf, /// The time of the recording. - time: NaiveDateTime, + time: DateTime<Utc>, /// The numeric ID of the boss. boss_id: u16, /// The name of the boss. @@ -423,7 +423,7 @@ fn extract_info(entry: &DirEntry, log: &Log) -> LogResult { LogResult { log_file: entry.path().to_path_buf(), - time: NaiveDateTime::from_timestamp(i64::from(log.local_start_timestamp().unwrap_or(0)), 0), + time: Utc.timestamp(i64::from(log.local_start_timestamp().unwrap_or(0)), 0), boss_id: log.encounter_id(), boss_name, players, diff --git a/src/output/formats.rs b/src/output/formats.rs index a608eab..10d84fc 100644 --- a/src/output/formats.rs +++ b/src/output/formats.rs @@ -4,6 +4,8 @@ use std::fmt::Write; use super::super::guilds; use super::{FightOutcome, LogResult}; +use chrono::Local; + /// An output format pub trait Format: Sync + Send { /// Format a single log result @@ -30,7 +32,9 @@ impl Format for HumanReadable { result, "{}: {} - {}: {} {}", "Date".green(), - item.time.format("%Y-%m-%d %H:%M:%S %a"), + item.time + .with_timezone(&Local) + .format("%Y-%m-%d %H:%M:%S %a"), "Boss".green(), item.boss_name, outcome, |