From cdd9158eedf81f3b962bf63f8d49346fcdccf8e6 Mon Sep 17 00:00:00 2001 From: ishiko Date: Sun, 5 Jan 2025 15:18:49 +0800 Subject: [PATCH] Fix/wrong calc elapsed days (#144) * Fix/incorrect calc of elapsed_days * add test * bump version to 4.5.2 --- __tests__/fixed/calc-elapsed-days.test.ts | 26 +++++++++++++++++++++++ package.json | 2 +- src/fsrs/abstract_scheduler.ts | 4 ++-- src/fsrs/default.ts | 2 +- src/fsrs/help.ts | 16 ++++++++++++++ 5 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 __tests__/fixed/calc-elapsed-days.test.ts diff --git a/__tests__/fixed/calc-elapsed-days.test.ts b/__tests__/fixed/calc-elapsed-days.test.ts new file mode 100644 index 0000000..792c97f --- /dev/null +++ b/__tests__/fixed/calc-elapsed-days.test.ts @@ -0,0 +1,26 @@ +import { createEmptyCard, fsrs, Grade, Rating } from '../../src/fsrs' + +/** + * @see https://forums.ankiweb.net/t/feature-request-estimated-total-knowledge-over-time/53036/58?u=l.m.sherlock + * @see https://ankiweb.net/shared/info/1613056169 + */ +test('TS-FSRS-Simulator', () => { + const f = fsrs({ + w: [ + 1.1596, 1.7974, 13.1205, 49.3729, 7.2303, 0.5081, 1.5371, 0.001, 1.5052, + 0.1261, 0.9735, 1.8924, 0.1486, 0.2407, 2.1937, 0.1518, 3.0699, 0.4636, + 0.6048, + ], + }) + const rids = [1704468957000, 1704469645000, 1704599572000, 1705509507000] + + const expected = [13.1205, 17.3668145, 21.28550751, 39.63452215] + let card = createEmptyCard(new Date(rids[0])) + const grades: Grade[] = [Rating.Good, Rating.Good, Rating.Good, Rating.Good] + for (let i = 0; i < rids.length; i++) { + const now = new Date(rids[i]) + const log = f.next(card, now, grades[i]) + card = log.card + expect(card.stability).toBeCloseTo(expected[i], 4) + } +}) diff --git a/package.json b/package.json index a0a81c0..1926dbe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts-fsrs", - "version": "4.5.1", + "version": "4.5.2", "description": "ts-fsrs is a versatile package based on TypeScript that supports ES modules, CommonJS, and UMD. It implements the Free Spaced Repetition Scheduler (FSRS) algorithm, enabling developers to integrate FSRS into their flashcard applications to enhance the user learning experience.", "main": "dist/index.cjs", "umd": "dist/index.umd.js", diff --git a/src/fsrs/abstract_scheduler.ts b/src/fsrs/abstract_scheduler.ts index ffbc185..9b53288 100644 --- a/src/fsrs/abstract_scheduler.ts +++ b/src/fsrs/abstract_scheduler.ts @@ -1,6 +1,6 @@ import { FSRSAlgorithm } from './algorithm' import { TypeConvert } from './convert' -import { Grades } from './help' +import { dateDiffInDays, Grades } from './help' import { type Card, type Grade, @@ -46,7 +46,7 @@ export abstract class AbstractScheduler implements IScheduler { const { state, last_review } = this.current let interval = 0 // card.state === State.New => 0 if (state !== State.New && last_review) { - interval = this.review_time.diff(last_review as Date, 'days') + interval = dateDiffInDays(last_review, this.review_time) } this.current.last_review = this.review_time this.current.elapsed_days = interval diff --git a/src/fsrs/default.ts b/src/fsrs/default.ts index 6902b2f..28c1f23 100644 --- a/src/fsrs/default.ts +++ b/src/fsrs/default.ts @@ -11,7 +11,7 @@ export const default_w = [ export const default_enable_fuzz = false export const default_enable_short_term = true -export const FSRSVersion: string = 'v4.5.1 using FSRS-5.0' +export const FSRSVersion: string = 'v4.5.2 using FSRS-5.0' export const generatorParameters = ( props?: Partial diff --git a/src/fsrs/help.ts b/src/fsrs/help.ts index 8d63eda..d9b4f46 100644 --- a/src/fsrs/help.ts +++ b/src/fsrs/help.ts @@ -191,3 +191,19 @@ export function get_fuzz_range( export function clamp(value: number, min: number, max: number): number { return Math.min(Math.max(value, min), max) } + +export function dateDiffInDays(last: Date, cur: Date) { + // Discard the time and time-zone information. + const utc1 = Date.UTC( + last.getUTCFullYear(), + last.getUTCMonth(), + last.getUTCDate() + ) + const utc2 = Date.UTC( + cur.getUTCFullYear(), + cur.getUTCMonth(), + cur.getUTCDate() + ) + + return Math.floor((utc2 - utc1) / 86400000 /** 1000 * 60 * 60 * 24*/) +}