> 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.

# Chrono overview

Chrono defines how a scheduler represents time, measures elapsed days, and calculates the next due time. The model works with intervals in days; Chrono connects those intervals to your application's time values.

## Choose a preset

Import `dateChrono`, `numericChrono`, `temporalInstantChrono`, and `defineChrono` from `ts-fsrs`.

| Preset                  | Time values        | Day arithmetic                                                                                                                                                                              |
| ----------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dateChrono`            | JavaScript `Date`  | `difference` counts UTC date boundaries by default; with `fractionalDays: true`, it measures elapsed time in fixed 24-hour days. `add` always adds fixed 24-hour days, including fractions. |
| `numericChrono`         | Numbers in days    | `difference(from, to)` is `to - from`; `add(from, days)` is `from + days`.                                                                                                                  |
| `temporalInstantChrono` | `Temporal.Instant` | Supports a configured timezone and optional fractional day differences.                                                                                                                     |

See the preset guides for details: [Date](https://open-spaced-repetition.github.io/ts-fsrs/guide/chrono/date.md), [Numeric](https://open-spaced-repetition.github.io/ts-fsrs/guide/chrono/numeric.md), and [Temporal Instant](https://open-spaced-repetition.github.io/ts-fsrs/guide/chrono/temporal-instant.md).

## Definition and runtime operations

A `Chrono` definition contains `schema`, `normalize`, `defaultValue`, and `create`. Pass the definition to `defineScheduler({ model, chrono })`; call its `create({ config })` when you need the time operations directly. The scheduler also exposes its configured runtime as `scheduler.chrono`.

For Date and Temporal, pass the complete configuration to `create({ config })`; only presets without configuration, such as Numeric, support `create()` without arguments. Scheduler creation validates configuration and supplies schema defaults.

| Operation              | Meaning                                                                                     |
| ---------------------- | ------------------------------------------------------------------------------------------- |
| `now()`                | Supplies a time value when the caller omits `now`.                                          |
| `difference(from, to)` | Returns elapsed days for the model.                                                         |
| `add(from, days)`      | Converts the final interval in days into a due time.                                        |
| `compare(left, right)` | Optional exact ordering: negative, zero, or positive. Date and Temporal presets provide it. |

## What normalize does

`normalize` is a `ChronoTimeNormalizer` Standard Schema whose output is `ChronoNormalizedTime<Time>`: `{ previous: Time | null, current: Time }`. `defineChrono` accepts either a compatible schema or a validation callback returning `{ value }` or `{ issues }`. `previous: null` means there is no previous event.

`normalize` translates a Chrono's concrete time fields into `{ previous, current }`, so the scheduler can calculate elapsed days and restore time fields during rollback without knowing the card or revlog field names. During review it receives `{ card, time: now }` (or only `{ time }` for a Chrono without card fields); during rollback it receives `{ revlog }`.

For Date and Temporal, `previous` is `lastReviewAt` and `current` is `dueAt`, not the current review time `now`. Numeric has no stored time fields and returns `{ previous: 0, current: time }`. The mapping belongs to the Chrono implementation; see [Date](https://open-spaced-repetition.github.io/ts-fsrs/guide/chrono/date.md) for the review and rollback flow.

`normalize` reads the time representation; `defaultValue` writes the scheduler's time values back into concrete card and revlog fields. Together they keep the scheduler independent of the stored field names.

## Customize elapsed days with defineChrono

This example keeps the Date preset's schemas, time normalizer, defaults, and precise comparison, but measures elapsed time in fixed 24-hour days with fractions. Reusing those parts preserves input validation and the card/revlog contract. If you change the stored fields, define matching schemas, review and rollback normalizers, and defaults together.

For fractional elapsed days, the built-in `dateChrono.create({ config: { fractionalDays: true } })` already provides this behavior. The following custom definition demonstrates how to override an operation with `defineChrono`.

```ts twoslash file="../../../snippets/run-code/chrono.ts" fold height=420
import { dateChrono, defineChrono } from 'ts-fsrs'

const millisecondsPerDay = 86_400_000

// Keep Date validation, card/revlog fields, and time normalization from the preset.
const fractionalDateChrono = defineChrono({
  schema: dateChrono.schema,
  normalize: dateChrono.normalize,
  defaultValue: dateChrono.defaultValue,
  create(ctx) {
    return {
      ...dateChrono.create(ctx),
      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 clock = fractionalDateChrono.create({ config: { fractionalDays: false } })

console.log(
  JSON.stringify(
    {
      utcDateDifference: dateChrono
        .create({ config: { fractionalDays: false } })
        .difference(from, now),
      fractionalDifference: clock.difference(from, now),
      halfDayLater: clock.add(from, 0.5).toISOString(),
    },
    null,
    2
  )
)

```


▶ Run code

The two-hour gap yields `1` with the UTC-date preset and `0.08333333333333333` with the custom Chrono. Calling `add(from, 0.5)` adds twelve hours, giving January 2 at 11:00 UTC.

This custom Chrono measures fixed durations; it does not account for local calendar days or daylight saving. Choose the Temporal preset when those calendar rules are needed. See [Architecture](https://open-spaced-repetition.github.io/ts-fsrs/guide/architecture.md) for choosing the model and scheduling policies.
