diff --git a/proto/backend.proto b/proto/backend.proto index 3821ad49f..66bcebf25 100644 --- a/proto/backend.proto +++ b/proto/backend.proto @@ -6,6 +6,10 @@ package backend_proto; message Empty {} +message OptionalInt32 { + sint32 val = 1; +} + message BackendInit { repeated string preferred_langs = 1; string locale_folder_path = 2; @@ -163,10 +167,10 @@ message TemplateRequirementAny { message SchedTimingTodayIn { int64 created_secs = 1; - sint32 created_mins_west = 2; - int64 now_secs = 3; - sint32 now_mins_west = 4; - sint32 rollover_hour = 5; + int64 now_secs = 2; + OptionalInt32 created_mins_west = 3; + OptionalInt32 now_mins_west = 4; + OptionalInt32 rollover_hour = 5; } message SchedTimingTodayOut { diff --git a/pylib/anki/rsbackend.py b/pylib/anki/rsbackend.py index b3d055577..ffad4e277 100644 --- a/pylib/anki/rsbackend.py +++ b/pylib/anki/rsbackend.py @@ -30,6 +30,7 @@ from anki.fluent_pb2 import FluentString as TR from anki.models import AllTemplateReqs from anki.sound import AVTag, SoundOrVideoTag, TTSTag from anki.types import assert_impossible_literal +from anki.utils import intTime assert ankirspy.buildhash() == anki.buildinfo.buildhash @@ -276,19 +277,33 @@ class RustBackend: def sched_timing_today( self, created_secs: int, - created_mins_west: int, - now_secs: int, - now_mins_west: int, - rollover: int, + created_mins_west: Optional[int], + now_mins_west: Optional[int], + rollover: Optional[int], ) -> SchedTimingToday: + if created_mins_west is not None: + crt_west = pb.OptionalInt32(val=created_mins_west) + else: + crt_west = None + + if now_mins_west is not None: + now_west = pb.OptionalInt32(val=now_mins_west) + else: + now_west = None + + if rollover is not None: + roll = pb.OptionalInt32(val=rollover) + else: + roll = None + return self._run_command( pb.BackendInput( sched_timing_today=pb.SchedTimingTodayIn( created_secs=created_secs, - created_mins_west=created_mins_west, - now_secs=now_secs, - now_mins_west=now_mins_west, - rollover_hour=rollover, + now_secs=intTime(), + created_mins_west=crt_west, + now_mins_west=now_west, + rollover_hour=roll, ) ) ).sched_timing_today diff --git a/pylib/anki/sched.py b/pylib/anki/sched.py index 0f696934b..7aacb97cd 100644 --- a/pylib/anki/sched.py +++ b/pylib/anki/sched.py @@ -867,10 +867,9 @@ did = ?, queue = %s, due = ?, usn = ? where id = ?""" def _updateCutoff(self) -> None: oldToday = self.today - # days since col created - self.today = int((time.time() - self.col.crt) // 86400) - # end of day cutoff - self.dayCutoff = self.col.crt + (self.today + 1) * 86400 + timing = self._timing_today() + self.today = timing.days_elapsed + self.dayCutoff = timing.next_day_at if oldToday != self.today: self.col.log(self.today, self.dayCutoff) # update all daily counts, but don't save decks to prevent needless diff --git a/pylib/anki/schedv2.py b/pylib/anki/schedv2.py index ad72381aa..0b8050887 100644 --- a/pylib/anki/schedv2.py +++ b/pylib/anki/schedv2.py @@ -3,7 +3,6 @@ from __future__ import annotations -import datetime import itertools import random import time @@ -1353,13 +1352,8 @@ where id = ? def _updateCutoff(self) -> None: oldToday = self.today timing = self._timing_today() - - if self._new_timezone_enabled(): - self.today = timing.days_elapsed - self.dayCutoff = timing.next_day_at - else: - self.today = self._daysSinceCreation() - self.dayCutoff = self._dayCutoff() + self.today = timing.days_elapsed + self.dayCutoff = timing.next_day_at if oldToday != self.today: self.col.log(self.today, self.dayCutoff) @@ -1385,51 +1379,28 @@ where id = ? if time.time() > self.dayCutoff: self.reset() - def _dayCutoff(self) -> int: - rolloverTime = self.col.conf.get("rollover", 4) - if rolloverTime < 0: - rolloverTime = 24 + rolloverTime - date = datetime.datetime.today() - date = date.replace(hour=rolloverTime, minute=0, second=0, microsecond=0) - if date < datetime.datetime.today(): - date = date + datetime.timedelta(days=1) - - stamp = int(time.mktime(date.timetuple())) - return stamp - - def _daysSinceCreation(self) -> int: - startDate = datetime.datetime.fromtimestamp(self.col.crt) - startDate = startDate.replace( - hour=self._rolloverHour(), minute=0, second=0, microsecond=0 - ) - return int((time.time() - time.mktime(startDate.timetuple())) // 86400) - def _rolloverHour(self) -> int: return self.col.conf.get("rollover", 4) # New timezone handling ########################################################################## - def _new_timezone_enabled(self) -> bool: - return self.col.conf.get("creationOffset") is not None - def _timing_today(self) -> SchedTimingToday: return self.col.backend.sched_timing_today( self.col.crt, self._creation_timezone_offset(), - intTime(), self._current_timezone_offset(), self._rolloverHour(), ) - def _current_timezone_offset(self) -> int: + def _current_timezone_offset(self) -> Optional[int]: if self.col.server: - return self.col.conf.get("localOffset", 0) + return self.col.conf.get("localOffset", None) else: - return self.col.backend.local_minutes_west(intTime()) + return None - def _creation_timezone_offset(self) -> int: - return self.col.conf.get("creationOffset", 0) + def _creation_timezone_offset(self) -> Optional[int]: + return self.col.conf.get("creationOffset", None) def set_creation_offset(self): """Save the UTC west offset at the time of creation into the DB. diff --git a/rslib/src/backend/mod.rs b/rslib/src/backend/mod.rs index 8bbba11a7..0240d8e9d 100644 --- a/rslib/src/backend/mod.rs +++ b/rslib/src/backend/mod.rs @@ -13,7 +13,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_v2_new}; +use crate::sched::cutoff::{local_minutes_west_for_stamp, sched_timing_today}; use crate::sched::timespan::{answer_button_time, learning_congrats, studied_today, time_span}; use crate::search::{search_cards, search_notes, SortMode}; use crate::template::{ @@ -350,12 +350,12 @@ impl Backend { } fn sched_timing_today(&self, input: pb::SchedTimingTodayIn) -> pb::SchedTimingTodayOut { - let today = sched_timing_today_v2_new( + let today = sched_timing_today( input.created_secs as i64, - input.created_mins_west, input.now_secs as i64, - input.now_mins_west, - input.rollover_hour as i8, + input.created_mins_west.map(|v| v.val), + input.now_mins_west.map(|v| v.val), + input.rollover_hour.map(|v| v.val as i8), ); pb::SchedTimingTodayOut { days_elapsed: today.days_elapsed, diff --git a/rslib/src/sched/cutoff.rs b/rslib/src/sched/cutoff.rs index 04bdb60fa..8ba4de722 100644 --- a/rslib/src/sched/cutoff.rs +++ b/rslib/src/sched/cutoff.rs @@ -1,7 +1,6 @@ // 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)] @@ -140,26 +139,25 @@ fn sched_timing_today_v2_legacy( /// Based on provided input, get timing info from the relevant function. pub(crate) fn sched_timing_today( created_secs: i64, + now_secs: i64, created_mins_west: Option, now_mins_west: Option, rollover_hour: Option, ) -> 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) + sched_timing_today_v1(created_secs, now_secs) } (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) + let offset = local_minutes_west_for_stamp(now_secs); + sched_timing_today_v2_legacy(created_secs, roll, now_secs, 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) + let now_west = now_mins_west.unwrap_or_else(|| local_minutes_west_for_stamp(now_secs)); + sched_timing_today_v2_new(created_secs, crt_west, now_secs, now_west, roll) } } } diff --git a/rslib/src/storage/sqlite.rs b/rslib/src/storage/sqlite.rs index 23d6eec1b..bbda2fab9 100644 --- a/rslib/src/storage/sqlite.rs +++ b/rslib/src/storage/sqlite.rs @@ -324,6 +324,7 @@ impl StorageContext<'_> { self.timing_today = Some(sched_timing_today( crt, + i64_unix_secs(), conf.creation_offset, now_offset, conf.rollover,