diff --git a/rslib/src/dbcheck.rs b/rslib/src/dbcheck.rs index 46fb95c3a..e13c97b5e 100644 --- a/rslib/src/dbcheck.rs +++ b/rslib/src/dbcheck.rs @@ -206,7 +206,8 @@ impl Collection { let nids_by_notetype = self.storage.all_note_ids_by_notetype()?; let norm = self.get_config_bool(BoolKey::NormalizeNoteText); let usn = self.usn()?; - let stamp = TimestampMillis::now(); + let stamp_millis = TimestampMillis::now(); + let stamp_secs = TimestampSecs::now(); let expanded_tags = self.storage.expanded_tags()?; self.storage.clear_all_tags()?; @@ -221,7 +222,7 @@ impl Collection { None => { let first_note = self.storage.get_note(group.peek().unwrap().1)?.unwrap(); out.notetypes_recovered += 1; - self.recover_notetype(stamp, first_note.fields().len(), ntid)? + self.recover_notetype(stamp_millis, first_note.fields().len(), ntid)? } Some(nt) => nt, }; @@ -252,6 +253,10 @@ impl Collection { out.field_count_mismatch += 1; } + if note.mtime > stamp_secs { + note.mtime = stamp_secs; + } + // note type ID may have changed if we created a recovery notetype note.notetype_id = nt.id; diff --git a/rslib/src/scheduler/mod.rs b/rslib/src/scheduler/mod.rs index 577d69ff4..45739d699 100644 --- a/rslib/src/scheduler/mod.rs +++ b/rslib/src/scheduler/mod.rs @@ -90,7 +90,7 @@ impl Collection { .and_then(|v| FixedOffset::west_opt(v * 60)) .unwrap_or_else(|| FixedOffset::west(0)); - let local_tz = TimestampSecs::now().local_utc_offset(); + let local_tz = TimestampSecs::now().local_utc_offset()?; Ok(if self.server { config_tz diff --git a/rslib/src/timestamp.rs b/rslib/src/timestamp.rs index 5a790ea35..d61c0b3fb 100644 --- a/rslib/src/timestamp.rs +++ b/rslib/src/timestamp.rs @@ -5,7 +5,7 @@ use std::time; use chrono::prelude::*; -use crate::define_newtype; +use crate::{define_newtype, prelude::*}; define_newtype!(TimestampSecs, i64); define_newtype!(TimestampMillis, i64); @@ -31,18 +31,33 @@ impl TimestampSecs { TimestampMillis(self.0 * 1000) } + #[cfg(windows)] + pub(crate) fn local_datetime(self) -> Result> { + std::panic::catch_unwind(|| Local.timestamp(self.0, 0)) + .map_err(|_err| AnkiError::invalid_input("invalid date")) + } + + #[cfg(not(windows))] + pub(crate) fn local_datetime(self) -> Result> { + Ok(Local.timestamp(self.0, 0)) + } + /// YYYY-mm-dd pub(crate) fn date_string(self) -> String { - Local.timestamp(self.0, 0).format("%Y-%m-%d").to_string() + self.local_datetime() + .map(|dt| dt.format("%Y-%m-%d").to_string()) + .unwrap_or_else(|_err| "invalid date".to_string()) } /// HH-MM pub(crate) fn time_string(self) -> String { - Local.timestamp(self.0, 0).format("%H:%M").to_string() + self.local_datetime() + .map(|dt| dt.format("%H:%M").to_string()) + .unwrap_or_else(|_err| "invalid date".to_string()) } - pub fn local_utc_offset(self) -> FixedOffset { - *Local.timestamp(self.0, 0).offset() + pub fn local_utc_offset(self) -> Result { + Ok(*self.local_datetime()?.offset()) } pub fn datetime(self, utc_offset: FixedOffset) -> DateTime {