switch next_day_at to a newtype

This commit is contained in:
Damien Elmes 2021-04-05 16:17:26 +10:00
parent 8d6b9d15a5
commit ebf7cc61d4
9 changed files with 51 additions and 40 deletions

View file

@ -180,7 +180,7 @@ impl From<crate::scheduler::timing::SchedTimingToday> for pb::SchedTimingTodayOu
fn from(t: crate::scheduler::timing::SchedTimingToday) -> pb::SchedTimingTodayOut { fn from(t: crate::scheduler::timing::SchedTimingToday) -> pb::SchedTimingTodayOut {
pb::SchedTimingTodayOut { pb::SchedTimingTodayOut {
days_elapsed: t.days_elapsed, days_elapsed: t.days_elapsed,
next_day_at: t.next_day_at, next_day_at: t.next_day_at.0,
} }
} }
} }

View file

@ -93,7 +93,7 @@ impl CardStateUpdater {
} }
fn secs_until_rollover(&self) -> u32 { 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 { fn into_card(self) -> Card {
@ -197,7 +197,7 @@ impl Collection {
let collapse_time = self.learn_ahead_secs(); let collapse_time = self.learn_ahead_secs();
let now = TimestampSecs::now(); let now = TimestampSecs::now();
let timing = self.timing_for_timestamp(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![ Ok(vec![
answer_button_time_collapsible( answer_button_time_collapsible(

View file

@ -66,7 +66,7 @@ impl CardQueues {
timing: SchedTimingToday, timing: SchedTimingToday,
) -> Option<LearningQueueEntry> { ) -> Option<LearningQueueEntry> {
// not due today? // 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; return None;
} }

View file

@ -10,7 +10,7 @@ pub struct SchedTimingToday {
/// The number of days that have passed since the collection was created. /// The number of days that have passed since the collection was created.
pub days_elapsed: u32, pub days_elapsed: u32,
/// Timestamp of the next day rollover. /// Timestamp of the next day rollover.
pub next_day_at: i64, pub next_day_at: TimestampSecs,
} }
/// Timing information for the current day. /// Timing information for the current day.
@ -34,11 +34,11 @@ pub fn sched_timing_today_v2_new(
// rollover // rollover
let rollover_today_datetime = today.and_hms(rollover_hour as u32, 0, 0); let rollover_today_datetime = today.and_hms(rollover_hour as u32, 0, 0);
let rollover_passed = rollover_today_datetime <= now_datetime; 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() (rollover_today_datetime + Duration::days(1)).timestamp()
} else { } else {
rollover_today_datetime.timestamp() rollover_today_datetime.timestamp()
}; });
// day count // day count
let days_elapsed = days_elapsed(created_date, today, rollover_passed); 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 { fn sched_timing_today_v1(crt: TimestampSecs, now: TimestampSecs) -> SchedTimingToday {
let days_elapsed = (now.0 - crt.0) / 86_400; 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 { SchedTimingToday {
now, now,
days_elapsed: days_elapsed as u32, days_elapsed: days_elapsed as u32,
@ -140,13 +140,14 @@ fn sched_timing_today_v2_legacy(
.timestamp(); .timestamp();
let days_elapsed = (now.0 - crt_at_rollover) / 86_400; let days_elapsed = (now.0 - crt_at_rollover) / 86_400;
let mut next_day_at = now let mut next_day_at = TimestampSecs(
.datetime(current_utc_offset) now.datetime(current_utc_offset)
.date() .date()
.and_hms(rollover as u32, 0, 0) .and_hms(rollover as u32, 0, 0)
.timestamp(); .timestamp(),
if next_day_at < now.0 { );
next_day_at += 86_400; if next_day_at < now {
next_day_at = next_day_at.adding_secs(86_400);
} }
SchedTimingToday { SchedTimingToday {
@ -321,7 +322,7 @@ mod test {
*now.offset(), *now.offset(),
rollhour as u8, 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 // after the rollover, the next day should be the next day
let now = Local.ymd(2019, 1, 3).and_hms(rollhour, 0, 0); let now = Local.ymd(2019, 1, 3).and_hms(rollhour, 0, 0);
@ -333,7 +334,7 @@ mod test {
*now.offset(), *now.offset(),
rollhour as u8, 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 // after the rollover, the next day should be the next day
let now = Local.ymd(2019, 1, 3).and_hms(rollhour + 3, 0, 0); let now = Local.ymd(2019, 1, 3).and_hms(rollhour + 3, 0, 0);
@ -345,7 +346,7 @@ mod test {
*now.offset(), *now.offset(),
rollhour as u8, 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] #[test]
@ -357,7 +358,7 @@ mod test {
SchedTimingToday { SchedTimingToday {
now, now,
days_elapsed: 107, days_elapsed: 107,
next_day_at: 1584558000 next_day_at: TimestampSecs(1584558000)
} }
); );
@ -366,7 +367,7 @@ mod test {
SchedTimingToday { SchedTimingToday {
now, now,
days_elapsed: 589, days_elapsed: 589,
next_day_at: 1584540000 next_day_at: TimestampSecs(1584540000)
} }
); );
@ -375,7 +376,7 @@ mod test {
SchedTimingToday { SchedTimingToday {
now, now,
days_elapsed: 700, days_elapsed: 700,
next_day_at: 1584554400 next_day_at: TimestampSecs(1584554400)
} }
); );
} }

View file

@ -210,8 +210,8 @@ impl SqlWriter<'_> {
fn write_rated(&mut self, op: &str, days: i64, ease: &RatingKind) -> Result<()> { fn write_rated(&mut self, op: &str, days: i64, ease: &RatingKind) -> Result<()> {
let today_cutoff = self.col.timing_today()?.next_day_at; let today_cutoff = self.col.timing_today()?.next_day_at;
let target_cutoff_ms = (today_cutoff + 86_400 * days) * 1_000; let target_cutoff_ms = today_cutoff.adding_secs(86_400 * days).as_millis();
let day_before_cutoff_ms = (today_cutoff + 86_400 * (days - 1)) * 1_000; 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(); write!(self.sql, "c.id in (select cid from revlog where id").unwrap();
@ -224,13 +224,13 @@ impl SqlWriter<'_> {
self.sql, self.sql,
" between {} and {}", " between {} and {}",
day_before_cutoff_ms, day_before_cutoff_ms,
target_cutoff_ms - 1 target_cutoff_ms.0 - 1
), ),
"!=" => write!( "!=" => write!(
self.sql, self.sql,
" not between {} and {}", " not between {} and {}",
day_before_cutoff_ms, day_before_cutoff_ms,
target_cutoff_ms - 1 target_cutoff_ms.0 - 1
), ),
_ => unreachable!("unexpected op"), _ => unreachable!("unexpected op"),
} }
@ -479,14 +479,14 @@ impl SqlWriter<'_> {
fn write_added(&mut self, days: u32) -> Result<()> { fn write_added(&mut self, days: u32) -> Result<()> {
let timing = self.col.timing_today()?; 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(); write!(self.sql, "c.id > {}", cutoff).unwrap();
Ok(()) Ok(())
} }
fn write_edited(&mut self, days: u32) -> Result<()> { fn write_edited(&mut self, days: u32) -> Result<()> {
let timing = self.col.timing_today()?; 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(); write!(self.sql, "n.mod > {}", cutoff).unwrap();
Ok(()) Ok(())
} }
@ -646,7 +646,7 @@ mod test {
let timing = ctx.timing_today().unwrap(); let timing = ctx.timing_today().unwrap();
assert_eq!( assert_eq!(
s(ctx, "added:3").0, 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,); assert_eq!(s(ctx, "added:0").0, s(ctx, "added:1").0,);
@ -730,14 +730,14 @@ mod test {
s(ctx, "rated:2").0, s(ctx, "rated:2").0,
format!( format!(
"(c.id in (select cid from revlog where id >= {} and ease > 0))", "(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!( assert_eq!(
s(ctx, "rated:400:1").0, s(ctx, "rated:400:1").0,
format!( format!(
"(c.id in (select cid from revlog where id >= {} and ease = 1))", "(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); assert_eq!(s(ctx, "rated:0").0, s(ctx, "rated:1").0);
@ -747,7 +747,7 @@ mod test {
s(ctx, "resched:400").0, s(ctx, "resched:400").0,
format!( format!(
"(c.id in (select cid from revlog where id >= {} and ease = 0))", "(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
) )
); );

View file

@ -22,11 +22,13 @@ impl Collection {
fn graph_data(&mut self, all: bool, days: u32) -> Result<pb::GraphsOut> { fn graph_data(&mut self, all: bool, days: u32) -> Result<pb::GraphsOut> {
let timing = self.timing_today()?; let timing = self.timing_today()?;
let revlog_start = TimestampSecs(if days > 0 { let revlog_start = if days > 0 {
timing.next_day_at - (((days as i64) + 1) * 86_400) timing
.next_day_at
.adding_secs(-(((days as i64) + 1) * 86_400))
} else { } else {
0 TimestampSecs(0)
}); };
let offset = self.local_utc_offset_for_user()?; let offset = self.local_utc_offset_for_user()?;
let local_offset_secs = offset.local_minus_utc() as i64; let local_offset_secs = offset.local_minus_utc() as i64;
@ -45,7 +47,7 @@ impl Collection {
cards: cards.into_iter().map(Into::into).collect(), cards: cards.into_iter().map(Into::into).collect(),
revlog, revlog,
days_elapsed: timing.days_elapsed, 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, scheduler_version: self.scheduler_version() as u32,
local_offset_secs: local_offset_secs as i32, local_offset_secs: local_offset_secs as i32,
}) })

View file

@ -169,7 +169,7 @@ impl super::SqliteStorage {
pub(crate) fn for_each_due_card_in_deck<F>( pub(crate) fn for_each_due_card_in_deck<F>(
&self, &self,
day_cutoff: u32, day_cutoff: u32,
learn_cutoff: i64, learn_cutoff: TimestampSecs,
deck: DeckId, deck: DeckId,
mut func: F, mut func: F,
) -> Result<()> ) -> Result<()>

View file

@ -133,11 +133,11 @@ impl SqliteStorage {
.collect() .collect()
} }
pub(crate) fn studied_today(&self, day_cutoff: i64) -> Result<StudiedToday> { pub(crate) fn studied_today(&self, day_cutoff: TimestampSecs) -> Result<StudiedToday> {
let start = (day_cutoff - 86_400) * 1_000; let start = day_cutoff.adding_secs(-86_400).as_millis();
self.db self.db
.prepare_cached(include_str!("studied_today.sql"))? .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 { Ok(StudiedToday {
cards: row.get(0)?, cards: row.get(0)?,
seconds: row.get(1)?, seconds: row.get(1)?,

View file

@ -19,10 +19,18 @@ impl TimestampSecs {
Self(0) Self(0)
} }
pub fn elapsed_secs_since(self, other: TimestampSecs) -> i64 {
self.0 - other.0
}
pub fn elapsed_secs(self) -> u64 { pub fn elapsed_secs(self) -> u64 {
(Self::now().0 - self.0).max(0) as u64 (Self::now().0 - self.0).max(0) as u64
} }
pub fn as_millis(self) -> TimestampMillis {
TimestampMillis(self.0 * 1000)
}
/// YYYY-mm-dd /// YYYY-mm-dd
pub(crate) fn date_string(self) -> String { pub(crate) fn date_string(self) -> String {
Local.timestamp(self.0, 0).format("%Y-%m-%d").to_string() Local.timestamp(self.0, 0).format("%Y-%m-%d").to_string()