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

Chrono の概要

Chrono は、スケジューラーが時間をどう表現し、経過日数と次の復習日時をどう計算するかを定めます。モデルは日単位の間隔を扱い、Chrono がその間隔をアプリケーションの時刻値に結び付けます。

プリセットを選ぶ

dateChrono、numericChrono、temporalInstantChrono、defineChrono は ts-fsrs からインポートできます。

プリセット時刻値日数の計算
dateChronoJavaScript Datedifference はデフォルトで UTC の日付差を計算し、fractionalDays: true では24時間単位の小数日数を返します。add は常に24時間単位で加算し、小数も扱えます。
numericChrono日単位の数値difference(from, to) は to - from、add(from, days) は from + days です。
temporalInstantChronoTemporal.Instantタイムゾーンを指定でき、日数差に小数部分を含めるかどうかも選べます。

各プリセットの詳細: Date、Numeric、Temporal Instant。

定義と実行時の操作

Chrono の定義には schema、normalize、defaultValue、create が含まれます。定義を defineScheduler({ model, chrono }) に渡します。時間演算だけを使いたい場合は、定義の create({ config }) を呼び出してください。設定済みの実行時オブジェクトには scheduler.chrono からもアクセスできます。

Date と Temporal の create({ config }) には完全な設定を渡してください。引数なしの create() は Numeric など設定が不要なプリセットで使えます。スケジューラーの生成時には設定の検証と schema のデフォルト値の補完が行われます。

操作役割
now()呼び出し側が now を省略したときに時刻値を返します。
difference(from, to)モデルが使う経過日数を返します。
add(from, days)最終的な日数間隔を次の復習日時に変換します。
compare(left, right)正確な前後関係を負数・ゼロ・正数で返す任意の操作です。Date と Temporal のプリセットで利用できます。

normalize の役割

normalize は ChronoTimeNormalizer 型の Standard Schema で、出力型は ChronoNormalizedTime<Time>({ previous: Time | null, current: Time })です。defineChrono は互換性のあるスキーマ、または { value } か { issues } を返す検証コールバックを受け取ります。previous: null は前回のイベントがないことを表します。

normalize は Chrono 固有の時刻フィールドを { previous, current } に変換します。これにより、スケジューラーは card や revlog のフィールド名を知らなくても、経過日数の計算やロールバック時の時刻フィールドの復元ができます。復習時には { card, time: now }(card フィールドを持たない Chrono では { time } のみ)、ロールバック時には { revlog } を受け取ります。

Date と Temporal では、previous は lastReviewAt、current は dueAt であり、今回の復習時刻 now ではありません。Numeric は時刻フィールドを保存せず、{ previous: 0, current: time } を返します。具体的な対応は Chrono の実装が決めます。復習とロールバックの流れは Date を参照してください。

normalize は時刻表現を読み取り、defaultValue はスケジューラーが渡す時刻値を具体的な card と revlog のフィールドに書き戻します。この組み合わせにより、スケジューラーを保存先のフィールド名から切り離せます。

defineChrono で経過日数をカスタマイズする

以下の例は Date プリセットの schema、normalize、デフォルト値、正確な時刻比較をそのまま使い、経過時間だけを24時間単位の小数日数に変更します。これらを再利用することで、入力検証と card/revlog のフィールドの整合性を保てます。保存するフィールドを変える場合は、対応する schema、復習とロールバックの normalize、デフォルト値をまとめて定義してください。

小数日数だけが必要なら、組み込みの dateChrono.create({ config: { fractionalDays: true } }) で対応できます。以下は defineChrono で操作を上書きする方法を示す例です。

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
,
function defineChrono<const Schema extends AnyChronoSchema>(definition: ChronoDefinition<Schema>): Chrono<ChronoDefinitionEnv<Schema>>
defineChrono
} from 'ts-fsrs'
const millisecondsPerDay = 86_400_000 // Keep Date validation, card/revlog fields, and time normalization from the preset. const
const fractionalDateChrono: Chrono<ChronoDefinitionEnv<{
    readonly time: SRSSchema<{
        input: Date;
        output: Date;
    }>;
} & {
    readonly config: SRSSchema<{
        input: {
            readonly fractionalDays?: boolean | undefined;
        };
        output: {
            readonly fractionalDays: boolean;
        };
    }>;
} & {
    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;
        };
    }>;
}>>
fractionalDateChrono
=
defineChrono<{
    readonly time: SRSSchema<{
        input: Date;
        output: Date;
    }>;
} & {
    readonly config: SRSSchema<{
        input: {
            readonly fractionalDays?: boolean | undefined;
        };
        output: {
            readonly fractionalDays: boolean;
        };
    }>;
} & {
    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;
        };
    }>;
}>(definition: ChronoDefinition<...>): Chrono<...>
defineChrono
({
schema: {
    readonly time: SRSSchema<{
        input: Date;
        output: Date;
    }>;
} & {
    readonly config: SRSSchema<{
        input: {
            readonly fractionalDays?: boolean | undefined;
        };
        output: {
            readonly fractionalDays: boolean;
        };
    }>;
} & {
    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;
        };
    }>;
}
schema
:
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; }; }>; }; }>.schema: {
    readonly time: SRSSchema<{
        input: Date;
        output: Date;
    }>;
} & {
    readonly config: SRSSchema<{
        input: {
            readonly fractionalDays?: boolean | undefined;
        };
        output: {
            readonly fractionalDays: boolean;
        };
    }>;
} & {
    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;
        };
    }>;
}
schema
,
normalize: ChronoTimeNormalizerDefinition<SRSSchema<{
    input: Date;
    output: Date;
}>, SRSSchema<{
    input: {
        dueAt: Date;
        lastReviewAt?: (Date | null) | undefined;
    };
    output: {
        dueAt: Date;
        lastReviewAt: Date | null;
    };
}>, SRSSchema<{
    input: {
        dueAt: Date;
        lastReviewAt?: (Date | null) | undefined;
        reviewTime: Date;
    };
    output: {
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
    };
}>>
normalize
:
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; }; }>; }; }>.normalize: ChronoTimeNormalizer<{
    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;
            };
        }>;
    };
}>
normalize
,
defaultValue?: Readonly<{
    readonly card?: FieldDefault<SRSSchema<{
        input: {
            dueAt: Date;
            lastReviewAt?: (Date | null) | undefined;
        };
        output: {
            dueAt: Date;
            lastReviewAt: Date | null;
        };
    }>, ChronoDefaultCtx<{
        readonly fractionalDays: boolean;
    }, Date, "card">> | undefined;
} & {
    readonly revlog?: FieldDefault<SRSSchema<{
        input: {
            dueAt: Date;
            lastReviewAt?: (Date | null) | undefined;
            reviewTime: Date;
        };
        output: {
            dueAt: Date;
            lastReviewAt: Date | null;
            reviewTime: Date;
        };
    }>, ChronoDefaultCtx<...>> | undefined;
}> | undefined
defaultValue
:
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; }; }>; }; }>.defaultValue: Readonly<{
    readonly card?: FieldDefault<SRSSchema<{
        input: {
            dueAt: Date;
            lastReviewAt?: (Date | null) | undefined;
        };
        output: {
            dueAt: Date;
            lastReviewAt: Date | null;
        };
    }>, ChronoDefaultCtx<{
        readonly fractionalDays: boolean;
    }, Date, "card">> | undefined;
} & {
    readonly revlog?: FieldDefault<SRSSchema<{
        input: {
            dueAt: Date;
            lastReviewAt?: (Date | null) | undefined;
            reviewTime: Date;
        };
        output: {
            dueAt: Date;
            lastReviewAt: Date | null;
            reviewTime: Date;
        };
    }>, ChronoDefaultCtx<...>> | undefined;
}>
defaultValue
,
create: (ctx: {
    readonly config: {
        readonly fractionalDays: boolean;
    };
}) => ChronoCore<Date>
create
(ctx) {
return { ...
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
(ctx),
ChronoCore<Date>.difference: (from: Date, to: Date) => number

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

difference
: (from, to) =>
(to.getTime() - from.getTime()) / millisecondsPerDay, } }, }) const from = new Date('2026-01-01T23:00:00.000Z') const now = new Date('2026-01-02T01:00:00.000Z') const
const clock: ChronoCore<Date>
clock
=
const fractionalDateChrono: Chrono<ChronoDefinitionEnv<{
    readonly time: SRSSchema<{
        input: Date;
        output: Date;
    }>;
} & {
    readonly config: SRSSchema<{
        input: {
            readonly fractionalDays?: boolean | undefined;
        };
        output: {
            readonly fractionalDays: boolean;
        };
    }>;
} & {
    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;
        };
    }>;
}>>
fractionalDateChrono
.
Chrono<ChronoDefinitionEnv<{ readonly time: SRSSchema<{ input: Date; output: Date; }>; } & { readonly config: SRSSchema<{ input: { readonly fractionalDays?: boolean | undefined; }; output: { readonly fractionalDays: boolean; }; }>; } & { ...; } & { ...; }>>.create: (ctx: {
    readonly config: {
        readonly fractionalDays: boolean;
    };
}) => ChronoCore<Date>
create
({ config: { fractionalDays: false } })
console.log( JSON.stringify( { utcDateDifference:
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 } })
.
ChronoCore<Date>.difference: (from: Date, to: Date) => number

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

difference
(from, now),
fractionalDifference:
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, now),
halfDayLater:
const clock: ChronoCore<Date>
clock
.
ChronoCore<Date>.add: (from: Date, days: number) => Date
add
(from, 0.5).toISOString(),
}, null, 2 ) )

同じ2時間の差でも、UTC 日付のプリセットでは 1、カスタム Chrono では 0.08333333333333333 になります。add(from, 0.5) は12時間を加算し、1月2日 11:00 UTC を返します。

このカスタム Chrono は固定の経過時間を計算し、現地の暦日や夏時間は扱いません。こうした暦のルールが必要な場合は Temporal プリセットを選んでください。モデルとスケジューリングポリシーの組み合わせ方はアーキテクチャを参照してください。