mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 23:12:21 -04:00
add v1 and v2 legacy timing code
This commit is contained in:
parent
9f3cc0982d
commit
2beccd377b
4 changed files with 147 additions and 9 deletions
|
@ -12,7 +12,7 @@ use crate::log::{default_logger, Logger};
|
|||
use crate::media::check::MediaChecker;
|
||||
use crate::media::sync::MediaSyncProgress;
|
||||
use crate::media::MediaManager;
|
||||
use crate::sched::cutoff::{local_minutes_west_for_stamp, sched_timing_today};
|
||||
use crate::sched::cutoff::{local_minutes_west_for_stamp, sched_timing_today_v2_new};
|
||||
use crate::sched::timespan::{answer_button_time, learning_congrats, studied_today, time_span};
|
||||
use crate::template::{
|
||||
render_card, without_legacy_template_directives, FieldMap, FieldRequirements, ParsedTemplate,
|
||||
|
@ -348,7 +348,7 @@ impl Backend {
|
|||
}
|
||||
|
||||
fn sched_timing_today(&self, input: pb::SchedTimingTodayIn) -> pb::SchedTimingTodayOut {
|
||||
let today = sched_timing_today(
|
||||
let today = sched_timing_today_v2_new(
|
||||
input.created_secs as i64,
|
||||
input.created_mins_west,
|
||||
input.now_secs as i64,
|
||||
|
|
|
@ -5,7 +5,11 @@ use crate::types::ObjID;
|
|||
use serde_derive::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Config {
|
||||
#[serde(rename = "curDeck")]
|
||||
pub(crate) current_deck_id: ObjID,
|
||||
pub(crate) rollover: Option<i8>,
|
||||
pub(crate) creation_offset: Option<i32>,
|
||||
pub(crate) local_offset: Option<i32>,
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::time::i64_unix_secs;
|
||||
use chrono::{Date, Duration, FixedOffset, Local, TimeZone};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub struct SchedTimingToday {
|
||||
/// The number of days that have passed since the collection was created.
|
||||
pub days_elapsed: u32,
|
||||
|
@ -17,7 +19,7 @@ pub struct SchedTimingToday {
|
|||
/// - now_secs is a timestamp of the current time
|
||||
/// - now_mins_west is the current offset west of UTC
|
||||
/// - rollover_hour is the hour of the day the rollover happens (eg 4 for 4am)
|
||||
pub fn sched_timing_today(
|
||||
pub fn sched_timing_today_v2_new(
|
||||
created_secs: i64,
|
||||
created_mins_west: i32,
|
||||
now_secs: i64,
|
||||
|
@ -90,11 +92,86 @@ pub fn local_minutes_west_for_stamp(stamp: i64) -> i32 {
|
|||
Local.timestamp(stamp, 0).offset().utc_minus_local() / 60
|
||||
}
|
||||
|
||||
// Legacy code
|
||||
// ----------------------------------
|
||||
|
||||
fn sched_timing_today_v1(crt: i64, now: i64) -> SchedTimingToday {
|
||||
let days_elapsed = (now - crt) / 86_400;
|
||||
let next_day_at = crt + (days_elapsed + 1) * 86_400;
|
||||
SchedTimingToday {
|
||||
days_elapsed: days_elapsed as u32,
|
||||
next_day_at,
|
||||
}
|
||||
}
|
||||
|
||||
fn sched_timing_today_v2_legacy(
|
||||
crt: i64,
|
||||
rollover: i8,
|
||||
now: i64,
|
||||
mins_west: i32,
|
||||
) -> SchedTimingToday {
|
||||
let normalized_rollover = normalized_rollover_hour(rollover);
|
||||
let offset = fixed_offset_from_minutes(mins_west);
|
||||
|
||||
let crt_at_rollover = offset
|
||||
.timestamp(crt, 0)
|
||||
.date()
|
||||
.and_hms(normalized_rollover as u32, 0, 0)
|
||||
.timestamp();
|
||||
let days_elapsed = (now - crt_at_rollover) / 86_400;
|
||||
|
||||
let mut next_day_at = offset
|
||||
.timestamp(now, 0)
|
||||
.date()
|
||||
.and_hms(normalized_rollover as u32, 0, 0)
|
||||
.timestamp();
|
||||
if next_day_at < now {
|
||||
next_day_at += 86_400;
|
||||
}
|
||||
|
||||
SchedTimingToday {
|
||||
days_elapsed: days_elapsed as u32,
|
||||
next_day_at,
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
|
||||
/// Based on provided input, get timing info from the relevant function.
|
||||
pub(crate) fn sched_timing_today(
|
||||
created_secs: i64,
|
||||
created_mins_west: Option<i32>,
|
||||
now_mins_west: Option<i32>,
|
||||
rollover_hour: Option<i8>,
|
||||
) -> SchedTimingToday {
|
||||
let now = i64_unix_secs();
|
||||
|
||||
match (rollover_hour, created_mins_west) {
|
||||
(None, _) => {
|
||||
// if rollover unset, v1 scheduler
|
||||
sched_timing_today_v1(created_secs, now)
|
||||
}
|
||||
(Some(roll), None) => {
|
||||
// if creation offset unset, v2 legacy cutoff using local timezone
|
||||
let offset = local_minutes_west_for_stamp(now);
|
||||
sched_timing_today_v2_legacy(created_secs, roll, now, offset)
|
||||
}
|
||||
(Some(roll), Some(crt_west)) => {
|
||||
// new cutoff code, using provided current timezone, falling back on local timezone
|
||||
let now_west = now_mins_west.unwrap_or_else(|| local_minutes_west_for_stamp(now));
|
||||
sched_timing_today_v2_new(created_secs, crt_west, now, now_west, roll)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::SchedTimingToday;
|
||||
use crate::sched::cutoff::sched_timing_today_v1;
|
||||
use crate::sched::cutoff::sched_timing_today_v2_legacy;
|
||||
use crate::sched::cutoff::{
|
||||
fixed_offset_from_minutes, local_minutes_west_for_stamp, normalized_rollover_hour,
|
||||
sched_timing_today,
|
||||
sched_timing_today_v2_new,
|
||||
};
|
||||
use chrono::{FixedOffset, Local, TimeZone, Utc};
|
||||
|
||||
|
@ -117,7 +194,7 @@ mod test {
|
|||
|
||||
// helper
|
||||
fn elap(start: i64, end: i64, start_west: i32, end_west: i32, rollhour: i8) -> u32 {
|
||||
let today = sched_timing_today(start, start_west, end, end_west, rollhour);
|
||||
let today = sched_timing_today_v2_new(start, start_west, end, end_west, rollhour);
|
||||
today.days_elapsed
|
||||
}
|
||||
|
||||
|
@ -228,7 +305,7 @@ mod test {
|
|||
// before the rollover, the next day should be later on the same day
|
||||
let now = Local.ymd(2019, 1, 3).and_hms(2, 0, 0);
|
||||
let next_day_at = Local.ymd(2019, 1, 3).and_hms(rollhour, 0, 0);
|
||||
let today = sched_timing_today(
|
||||
let today = sched_timing_today_v2_new(
|
||||
crt.timestamp(),
|
||||
crt.offset().utc_minus_local() / 60,
|
||||
now.timestamp(),
|
||||
|
@ -240,7 +317,7 @@ mod test {
|
|||
// after the rollover, the next day should be the next day
|
||||
let now = Local.ymd(2019, 1, 3).and_hms(rollhour, 0, 0);
|
||||
let next_day_at = Local.ymd(2019, 1, 4).and_hms(rollhour, 0, 0);
|
||||
let today = sched_timing_today(
|
||||
let today = sched_timing_today_v2_new(
|
||||
crt.timestamp(),
|
||||
crt.offset().utc_minus_local() / 60,
|
||||
now.timestamp(),
|
||||
|
@ -252,7 +329,7 @@ mod test {
|
|||
// 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 next_day_at = Local.ymd(2019, 1, 4).and_hms(rollhour, 0, 0);
|
||||
let today = sched_timing_today(
|
||||
let today = sched_timing_today_v2_new(
|
||||
crt.timestamp(),
|
||||
crt.offset().utc_minus_local() / 60,
|
||||
now.timestamp(),
|
||||
|
@ -261,4 +338,34 @@ mod test {
|
|||
);
|
||||
assert_eq!(today.next_day_at, next_day_at.timestamp());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_timing() {
|
||||
let now = 1584491078;
|
||||
let mins_west = -600;
|
||||
|
||||
assert_eq!(
|
||||
sched_timing_today_v1(1575226800, now),
|
||||
SchedTimingToday {
|
||||
days_elapsed: 107,
|
||||
next_day_at: 1584558000
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
sched_timing_today_v2_legacy(1533564000, 0, now, mins_west),
|
||||
SchedTimingToday {
|
||||
days_elapsed: 589,
|
||||
next_day_at: 1584540000
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
sched_timing_today_v2_legacy(1524038400, 4, now, mins_west),
|
||||
SchedTimingToday {
|
||||
days_elapsed: 700,
|
||||
next_day_at: 1584554400
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,11 @@ use crate::config::Config;
|
|||
use crate::err::Result;
|
||||
use crate::err::{AnkiError, DBErrorKind};
|
||||
use crate::time::{i64_unix_millis, i64_unix_secs};
|
||||
use crate::{decks::Deck, types::Usn};
|
||||
use crate::{
|
||||
decks::Deck,
|
||||
sched::cutoff::{sched_timing_today, SchedTimingToday},
|
||||
types::Usn,
|
||||
};
|
||||
use rusqlite::{params, Connection, NO_PARAMS};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
@ -121,6 +125,8 @@ pub(crate) struct StorageContext<'a> {
|
|||
server: bool,
|
||||
#[allow(dead_code)]
|
||||
usn: Option<Usn>,
|
||||
|
||||
timing_today: Option<SchedTimingToday>,
|
||||
}
|
||||
|
||||
impl StorageContext<'_> {
|
||||
|
@ -129,6 +135,7 @@ impl StorageContext<'_> {
|
|||
db,
|
||||
server,
|
||||
usn: None,
|
||||
timing_today: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,4 +232,24 @@ impl StorageContext<'_> {
|
|||
Ok(serde_json::from_str(row.get_raw(0).as_str()?)?)
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn timing_today(&mut self) -> Result<SchedTimingToday> {
|
||||
if self.timing_today.is_none() {
|
||||
let crt: i64 = self
|
||||
.db
|
||||
.prepare_cached("select crt from col")?
|
||||
.query_row(NO_PARAMS, |row| row.get(0))?;
|
||||
let conf = self.all_config()?;
|
||||
let now_offset = if self.server { conf.local_offset } else { None };
|
||||
|
||||
self.timing_today = Some(sched_timing_today(
|
||||
crt,
|
||||
conf.creation_offset,
|
||||
now_offset,
|
||||
conf.rollover,
|
||||
));
|
||||
}
|
||||
Ok(*self.timing_today.as_ref().unwrap())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue