For AI agents: the complete documentation index is available at https://open-spaced-repetition.github.io/ts-fsrs/llms.txt, the full documentation bundle is available at https://open-spaced-repetition.github.io/ts-fsrs/llms-full.txt, and this page is available as Markdown at https://open-spaced-repetition.github.io/ts-fsrs/guide/chrono/date.md.

Date

dateChrono is the preset used by DefaultScheduler. Its time schema accepts valid Date objects, so convert stored strings or timestamps to Date before calling the scheduler. The current schema also rejects new Date(0) (the exact Unix epoch) and invalid dates.

Configure Date with fractionalDays at the top level of the scheduler config (default false). Direct calls require dateChrono.create({ config: { fractionalDays: false } }). With false, two times which have the same UTC date have a difference of zero, and 23:00 to 01:00 the next day gives one day. With true, that two-hour gap gives 2 / 24 days. add(from, 0.5) always adds twelve hours. Use compare for precise ordering.

How normalize participates in scheduling

Normalization maps card or revlog fields to { previous, current }. For Date and Temporal presets:

  • During review, normalize returns previous: card.lastReviewAt and current: card.dueAt.
  • Elapsed days are difference(previous ?? current, now); New cards always use zero.
  • The next card stores dueAt: add(now, interval) and lastReviewAt: now.
  • The revlog stores the pre-review card’s dueAt and lastReviewAt, plus this review’s reviewTime: now.
  • During rollback, normalize returns previous: revlog.lastReviewAt and current: revlog.dueAt. These restore the pre-review card’s timestamps; a New card restores lastReviewAt: null.

Try the preset

import { 
const dateChrono: Chrono<{
    readonly time: SRSSchema<{
        input: Date;
        output: Date;
    }>;
    readonly config: SRSSchema<{
        input: {
            readonly fractionalDays?: boolean | undefined;
        };
        output: {
            readonly fractionalDays: boolean;
        };
    }>;
    readonly fields: {
        readonly card: SRSSchema<{
            input: {
                dueAt: Date;
                lastReviewAt?: (Date | null) | undefined;
            };
            output: {
                dueAt: Date;
                lastReviewAt: Date | null;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                dueAt: Date;
                lastReviewAt?: (Date | null) | undefined;
                reviewTime: Date;
            };
            output: {
                dueAt: Date;
                lastReviewAt: Date | null;
                reviewTime: Date;
            };
        }>;
    };
}>
dateChrono
} from 'ts-fsrs'
const
const clock: ChronoCore<Date>
clock
=
const dateChrono: Chrono<{
    readonly time: SRSSchema<{
        input: Date;
        output: Date;
    }>;
    readonly config: SRSSchema<{
        input: {
            readonly fractionalDays?: boolean | undefined;
        };
        output: {
            readonly fractionalDays: boolean;
        };
    }>;
    readonly fields: {
        readonly card: SRSSchema<{
            input: {
                dueAt: Date;
                lastReviewAt?: (Date | null) | undefined;
            };
            output: {
                dueAt: Date;
                lastReviewAt: Date | null;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                dueAt: Date;
                lastReviewAt?: (Date | null) | undefined;
                reviewTime: Date;
            };
            output: {
                dueAt: Date;
                lastReviewAt: Date | null;
                reviewTime: Date;
            };
        }>;
    };
}>
dateChrono
.
Chrono<{ readonly time: SRSSchema<{ input: Date; output: Date; }>; readonly config: SRSSchema<{ input: { readonly fractionalDays?: boolean | undefined; }; output: { readonly fractionalDays: boolean; }; }>; readonly fields: { readonly card: SRSSchema<{ input: { dueAt: Date; lastReviewAt?: (Date | null) | undefined; }; output: { dueAt: Date; lastReviewAt: Date | null; }; }>; readonly revlog: SRSSchema<{ input: { dueAt: Date; lastReviewAt?: (Date | null) | undefined; reviewTime: Date; }; output: { dueAt: Date; lastReviewAt: Date | null; reviewTime: Date; }; }>; }; }>.create: (ctx: {
    readonly config: {
        readonly fractionalDays: boolean;
    };
}) => ChronoCore<Date>
create
({ config: { fractionalDays: false } })
const from = new Date('2026-01-01T23:00:00.000Z') const to = new Date('2026-01-02T01:00:00.000Z') console.log( JSON.stringify({ elapsedDays:
const clock: ChronoCore<Date>
clock
.
ChronoCore<Date>.difference: (from: Date, to: Date) => number

Returns the distance from the previous review time to the current time.

difference
(from, to),
halfDayLater:
const clock: ChronoCore<Date>
clock
.
ChronoCore<Date>.add: (from: Date, days: number) => Date
add
(from, 0.5).toISOString(),
order:
const clock: ChronoCore<Date>
clock
.
ChronoCore<Date>.compare?: ((left: Date, right: Date) => number) | undefined

Compares two time values in chronological order.

Returns a negative number when left is earlier than right, zero when they are equal, and a positive number when left is later than right. Callers decide how to compare values when a chronology omits this method.

compare
?.(from, to),
}) )

Across midnight, the UTC date difference is one day; adding half a day advances the time by twelve hours.