diff --git a/rslib/src/backend/scheduler/mod.rs b/rslib/src/backend/scheduler/mod.rs index b5366a2a0..3f612bc91 100644 --- a/rslib/src/backend/scheduler/mod.rs +++ b/rslib/src/backend/scheduler/mod.rs @@ -180,7 +180,7 @@ impl From for pb::SchedTimingTodayOu fn from(t: crate::scheduler::timing::SchedTimingToday) -> pb::SchedTimingTodayOut { pb::SchedTimingTodayOut { days_elapsed: t.days_elapsed, - next_day_at: t.next_day_at, + next_day_at: t.next_day_at.0, } } } diff --git a/rslib/src/scheduler/answering/mod.rs b/rslib/src/scheduler/answering/mod.rs index fb5501291..c6ea0acd8 100644 --- a/rslib/src/scheduler/answering/mod.rs +++ b/rslib/src/scheduler/answering/mod.rs @@ -93,7 +93,7 @@ impl CardStateUpdater { } fn secs_until_rollover(&self) -> u32 { - (self.timing.next_day_at - self.now.0).max(0) as u32 + self.timing.next_day_at.elapsed_secs_since(self.now) as u32 } fn into_card(self) -> Card { @@ -197,7 +197,7 @@ impl Collection { let collapse_time = self.learn_ahead_secs(); let now = TimestampSecs::now(); let timing = self.timing_for_timestamp(now)?; - let secs_until_rollover = (timing.next_day_at - now.0).max(0) as u32; + let secs_until_rollover = timing.next_day_at.elapsed_secs_since(now).max(0) as u32; Ok(vec![ answer_button_time_collapsible( diff --git a/rslib/src/scheduler/queue/learning.rs b/rslib/src/scheduler/queue/learning.rs index 3d2cea37b..4ce4a713f 100644 --- a/rslib/src/scheduler/queue/learning.rs +++ b/rslib/src/scheduler/queue/learning.rs @@ -66,7 +66,7 @@ impl CardQueues { timing: SchedTimingToday, ) -> Option { // not due today? - if !card.is_intraday_learning() || card.due >= timing.next_day_at as i32 { + if !card.is_intraday_learning() || card.due >= timing.next_day_at.0 as i32 { return None; } diff --git a/rslib/src/scheduler/timing.rs b/rslib/src/scheduler/timing.rs index e5de473c5..6e5c154ba 100644 --- a/rslib/src/scheduler/timing.rs +++ b/rslib/src/scheduler/timing.rs @@ -10,7 +10,7 @@ pub struct SchedTimingToday { /// The number of days that have passed since the collection was created. pub days_elapsed: u32, /// Timestamp of the next day rollover. - pub next_day_at: i64, + pub next_day_at: TimestampSecs, } /// Timing information for the current day. @@ -34,11 +34,11 @@ pub fn sched_timing_today_v2_new( // rollover let rollover_today_datetime = today.and_hms(rollover_hour as u32, 0, 0); let rollover_passed = rollover_today_datetime <= now_datetime; - let next_day_at = if rollover_passed { + let next_day_at = TimestampSecs(if rollover_passed { (rollover_today_datetime + Duration::days(1)).timestamp() } else { rollover_today_datetime.timestamp() - }; + }); // day count let days_elapsed = days_elapsed(created_date, today, rollover_passed); @@ -119,7 +119,7 @@ fn v1_creation_date_adjusted_to_hour_inner(crt: i64, hour: u8, offset: FixedOffs fn sched_timing_today_v1(crt: TimestampSecs, now: TimestampSecs) -> SchedTimingToday { let days_elapsed = (now.0 - crt.0) / 86_400; - let next_day_at = crt.0 + (days_elapsed + 1) * 86_400; + let next_day_at = TimestampSecs(crt.0 + (days_elapsed + 1) * 86_400); SchedTimingToday { now, days_elapsed: days_elapsed as u32, @@ -140,13 +140,14 @@ fn sched_timing_today_v2_legacy( .timestamp(); let days_elapsed = (now.0 - crt_at_rollover) / 86_400; - let mut next_day_at = now - .datetime(current_utc_offset) - .date() - .and_hms(rollover as u32, 0, 0) - .timestamp(); - if next_day_at < now.0 { - next_day_at += 86_400; + let mut next_day_at = TimestampSecs( + now.datetime(current_utc_offset) + .date() + .and_hms(rollover as u32, 0, 0) + .timestamp(), + ); + if next_day_at < now { + next_day_at = next_day_at.adding_secs(86_400); } SchedTimingToday { @@ -321,7 +322,7 @@ mod test { *now.offset(), rollhour as u8, ); - assert_eq!(today.next_day_at, next_day_at.timestamp()); + assert_eq!(today.next_day_at.0, next_day_at.timestamp()); // after the rollover, the next day should be the next day let now = Local.ymd(2019, 1, 3).and_hms(rollhour, 0, 0); @@ -333,7 +334,7 @@ mod test { *now.offset(), rollhour as u8, ); - assert_eq!(today.next_day_at, next_day_at.timestamp()); + assert_eq!(today.next_day_at.0, next_day_at.timestamp()); // after the rollover, the next day should be the next day let now = Local.ymd(2019, 1, 3).and_hms(rollhour + 3, 0, 0); @@ -345,7 +346,7 @@ mod test { *now.offset(), rollhour as u8, ); - assert_eq!(today.next_day_at, next_day_at.timestamp()); + assert_eq!(today.next_day_at.0, next_day_at.timestamp()); } #[test] @@ -357,7 +358,7 @@ mod test { SchedTimingToday { now, days_elapsed: 107, - next_day_at: 1584558000 + next_day_at: TimestampSecs(1584558000) } ); @@ -366,7 +367,7 @@ mod test { SchedTimingToday { now, days_elapsed: 589, - next_day_at: 1584540000 + next_day_at: TimestampSecs(1584540000) } ); @@ -375,7 +376,7 @@ mod test { SchedTimingToday { now, days_elapsed: 700, - next_day_at: 1584554400 + next_day_at: TimestampSecs(1584554400) } ); } diff --git a/rslib/src/search/sqlwriter.rs b/rslib/src/search/sqlwriter.rs index 690343cec..3de6cbc41 100644 --- a/rslib/src/search/sqlwriter.rs +++ b/rslib/src/search/sqlwriter.rs @@ -210,8 +210,8 @@ impl SqlWriter<'_> { fn write_rated(&mut self, op: &str, days: i64, ease: &RatingKind) -> Result<()> { let today_cutoff = self.col.timing_today()?.next_day_at; - let target_cutoff_ms = (today_cutoff + 86_400 * days) * 1_000; - let day_before_cutoff_ms = (today_cutoff + 86_400 * (days - 1)) * 1_000; + let target_cutoff_ms = today_cutoff.adding_secs(86_400 * days).as_millis(); + let day_before_cutoff_ms = today_cutoff.adding_secs(86_400 * (days - 1)).as_millis(); write!(self.sql, "c.id in (select cid from revlog where id").unwrap(); @@ -224,13 +224,13 @@ impl SqlWriter<'_> { self.sql, " between {} and {}", day_before_cutoff_ms, - target_cutoff_ms - 1 + target_cutoff_ms.0 - 1 ), "!=" => write!( self.sql, " not between {} and {}", day_before_cutoff_ms, - target_cutoff_ms - 1 + target_cutoff_ms.0 - 1 ), _ => unreachable!("unexpected op"), } @@ -479,14 +479,14 @@ impl SqlWriter<'_> { fn write_added(&mut self, days: u32) -> Result<()> { let timing = self.col.timing_today()?; - let cutoff = (timing.next_day_at - (86_400 * (days as i64))) * 1_000; + let cutoff = (timing.next_day_at.0 - (86_400 * (days as i64))) * 1_000; write!(self.sql, "c.id > {}", cutoff).unwrap(); Ok(()) } fn write_edited(&mut self, days: u32) -> Result<()> { let timing = self.col.timing_today()?; - let cutoff = timing.next_day_at - (86_400 * (days as i64)); + let cutoff = timing.next_day_at.0 - (86_400 * (days as i64)); write!(self.sql, "n.mod > {}", cutoff).unwrap(); Ok(()) } @@ -646,7 +646,7 @@ mod test { let timing = ctx.timing_today().unwrap(); assert_eq!( s(ctx, "added:3").0, - format!("(c.id > {})", (timing.next_day_at - (86_400 * 3)) * 1_000) + format!("(c.id > {})", (timing.next_day_at.0 - (86_400 * 3)) * 1_000) ); assert_eq!(s(ctx, "added:0").0, s(ctx, "added:1").0,); @@ -730,14 +730,14 @@ mod test { s(ctx, "rated:2").0, format!( "(c.id in (select cid from revlog where id >= {} and ease > 0))", - (timing.next_day_at - (86_400 * 2)) * 1_000 + (timing.next_day_at.0 - (86_400 * 2)) * 1_000 ) ); assert_eq!( s(ctx, "rated:400:1").0, format!( "(c.id in (select cid from revlog where id >= {} and ease = 1))", - (timing.next_day_at - (86_400 * 400)) * 1_000 + (timing.next_day_at.0 - (86_400 * 400)) * 1_000 ) ); assert_eq!(s(ctx, "rated:0").0, s(ctx, "rated:1").0); @@ -747,7 +747,7 @@ mod test { s(ctx, "resched:400").0, format!( "(c.id in (select cid from revlog where id >= {} and ease = 0))", - (timing.next_day_at - (86_400 * 400)) * 1_000 + (timing.next_day_at.0 - (86_400 * 400)) * 1_000 ) ); diff --git a/rslib/src/stats/graphs.rs b/rslib/src/stats/graphs.rs index 3746a36a3..c425850dd 100644 --- a/rslib/src/stats/graphs.rs +++ b/rslib/src/stats/graphs.rs @@ -22,11 +22,13 @@ impl Collection { fn graph_data(&mut self, all: bool, days: u32) -> Result { let timing = self.timing_today()?; - let revlog_start = TimestampSecs(if days > 0 { - timing.next_day_at - (((days as i64) + 1) * 86_400) + let revlog_start = if days > 0 { + timing + .next_day_at + .adding_secs(-(((days as i64) + 1) * 86_400)) } else { - 0 - }); + TimestampSecs(0) + }; let offset = self.local_utc_offset_for_user()?; let local_offset_secs = offset.local_minus_utc() as i64; @@ -45,7 +47,7 @@ impl Collection { cards: cards.into_iter().map(Into::into).collect(), revlog, days_elapsed: timing.days_elapsed, - next_day_at_secs: timing.next_day_at as u32, + next_day_at_secs: timing.next_day_at.0 as u32, scheduler_version: self.scheduler_version() as u32, local_offset_secs: local_offset_secs as i32, }) diff --git a/rslib/src/storage/card/mod.rs b/rslib/src/storage/card/mod.rs index 7aad29c36..7bd54221f 100644 --- a/rslib/src/storage/card/mod.rs +++ b/rslib/src/storage/card/mod.rs @@ -169,7 +169,7 @@ impl super::SqliteStorage { pub(crate) fn for_each_due_card_in_deck( &self, day_cutoff: u32, - learn_cutoff: i64, + learn_cutoff: TimestampSecs, deck: DeckId, mut func: F, ) -> Result<()> diff --git a/rslib/src/storage/revlog/mod.rs b/rslib/src/storage/revlog/mod.rs index 67cf1861c..69495c032 100644 --- a/rslib/src/storage/revlog/mod.rs +++ b/rslib/src/storage/revlog/mod.rs @@ -133,11 +133,11 @@ impl SqliteStorage { .collect() } - pub(crate) fn studied_today(&self, day_cutoff: i64) -> Result { - let start = (day_cutoff - 86_400) * 1_000; + pub(crate) fn studied_today(&self, day_cutoff: TimestampSecs) -> Result { + let start = day_cutoff.adding_secs(-86_400).as_millis(); self.db .prepare_cached(include_str!("studied_today.sql"))? - .query_map(&[start, RevlogReviewKind::Manual as i64], |row| { + .query_map(&[start.0, RevlogReviewKind::Manual as i64], |row| { Ok(StudiedToday { cards: row.get(0)?, seconds: row.get(1)?, diff --git a/rslib/src/timestamp.rs b/rslib/src/timestamp.rs index d4fae5b4f..03330e6a9 100644 --- a/rslib/src/timestamp.rs +++ b/rslib/src/timestamp.rs @@ -19,10 +19,18 @@ impl TimestampSecs { Self(0) } + pub fn elapsed_secs_since(self, other: TimestampSecs) -> i64 { + self.0 - other.0 + } + pub fn elapsed_secs(self) -> u64 { (Self::now().0 - self.0).max(0) as u64 } + pub fn as_millis(self) -> TimestampMillis { + TimestampMillis(self.0 * 1000) + } + /// YYYY-mm-dd pub(crate) fn date_string(self) -> String { Local.timestamp(self.0, 0).format("%Y-%m-%d").to_string()