mirror of
https://github.com/ankitects/anki.git
synced 2025-09-21 15:32:23 -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::check::MediaChecker;
|
||||||
use crate::media::sync::MediaSyncProgress;
|
use crate::media::sync::MediaSyncProgress;
|
||||||
use crate::media::MediaManager;
|
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::sched::timespan::{answer_button_time, learning_congrats, studied_today, time_span};
|
||||||
use crate::template::{
|
use crate::template::{
|
||||||
render_card, without_legacy_template_directives, FieldMap, FieldRequirements, ParsedTemplate,
|
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 {
|
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_secs as i64,
|
||||||
input.created_mins_west,
|
input.created_mins_west,
|
||||||
input.now_secs as i64,
|
input.now_secs as i64,
|
||||||
|
|
|
@ -5,7 +5,11 @@ use crate::types::ObjID;
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
#[serde(rename = "curDeck")]
|
#[serde(rename = "curDeck")]
|
||||||
pub(crate) current_deck_id: ObjID,
|
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
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// 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};
|
use chrono::{Date, Duration, FixedOffset, Local, TimeZone};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub struct SchedTimingToday {
|
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,
|
||||||
|
@ -17,7 +19,7 @@ pub struct SchedTimingToday {
|
||||||
/// - now_secs is a timestamp of the current time
|
/// - now_secs is a timestamp of the current time
|
||||||
/// - now_mins_west is the current offset west of UTC
|
/// - 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)
|
/// - 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_secs: i64,
|
||||||
created_mins_west: i32,
|
created_mins_west: i32,
|
||||||
now_secs: i64,
|
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
|
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)]
|
#[cfg(test)]
|
||||||
mod 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::{
|
use crate::sched::cutoff::{
|
||||||
fixed_offset_from_minutes, local_minutes_west_for_stamp, normalized_rollover_hour,
|
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};
|
use chrono::{FixedOffset, Local, TimeZone, Utc};
|
||||||
|
|
||||||
|
@ -117,7 +194,7 @@ mod test {
|
||||||
|
|
||||||
// helper
|
// helper
|
||||||
fn elap(start: i64, end: i64, start_west: i32, end_west: i32, rollhour: i8) -> u32 {
|
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
|
today.days_elapsed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +305,7 @@ mod test {
|
||||||
// before the rollover, the next day should be later on the same day
|
// 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 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 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.timestamp(),
|
||||||
crt.offset().utc_minus_local() / 60,
|
crt.offset().utc_minus_local() / 60,
|
||||||
now.timestamp(),
|
now.timestamp(),
|
||||||
|
@ -240,7 +317,7 @@ mod test {
|
||||||
// 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);
|
||||||
let next_day_at = Local.ymd(2019, 1, 4).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.timestamp(),
|
||||||
crt.offset().utc_minus_local() / 60,
|
crt.offset().utc_minus_local() / 60,
|
||||||
now.timestamp(),
|
now.timestamp(),
|
||||||
|
@ -252,7 +329,7 @@ mod test {
|
||||||
// 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);
|
||||||
let next_day_at = Local.ymd(2019, 1, 4).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.timestamp(),
|
||||||
crt.offset().utc_minus_local() / 60,
|
crt.offset().utc_minus_local() / 60,
|
||||||
now.timestamp(),
|
now.timestamp(),
|
||||||
|
@ -261,4 +338,34 @@ mod test {
|
||||||
);
|
);
|
||||||
assert_eq!(today.next_day_at, next_day_at.timestamp());
|
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::Result;
|
||||||
use crate::err::{AnkiError, DBErrorKind};
|
use crate::err::{AnkiError, DBErrorKind};
|
||||||
use crate::time::{i64_unix_millis, i64_unix_secs};
|
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 rusqlite::{params, Connection, NO_PARAMS};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
@ -121,6 +125,8 @@ pub(crate) struct StorageContext<'a> {
|
||||||
server: bool,
|
server: bool,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
usn: Option<Usn>,
|
usn: Option<Usn>,
|
||||||
|
|
||||||
|
timing_today: Option<SchedTimingToday>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StorageContext<'_> {
|
impl StorageContext<'_> {
|
||||||
|
@ -129,6 +135,7 @@ impl StorageContext<'_> {
|
||||||
db,
|
db,
|
||||||
server,
|
server,
|
||||||
usn: None,
|
usn: None,
|
||||||
|
timing_today: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,4 +232,24 @@ impl StorageContext<'_> {
|
||||||
Ok(serde_json::from_str(row.get_raw(0).as_str()?)?)
|
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