---
id: "packages/active-format/changelog"
title: "Changelog"
description: "What changed for users of active-format, per version."
url: "/packages/active-format/changelog"
locale: "en"
revision: "8a1a95f1f7580db1"
---

# Changelog

> [!NOTE]
> **Release state**
>
> The version line at the top of this page is read from the package and the
> release register of Foundation. A version heading in the changelog below is
> not a release by itself: only a recorded release is. While the status says
> development, the content can still change before it is released.

Notable changes to `@workspace/active-format`. Format based on
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning per
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## \[Unreleased\]

### Documentation

- **No links to documents of another repository.** References to documents
  of the repository the package came from (Datyx) are text now, marked as
  such, instead of links that resolve nowhere (or to another document) in
  the repository that holds the package. The reuse section names the source
  repository's transfer standard instead of a Datyx path. No code changed.
- **`CurrencyFormatOptions.decimals` reads on its own.** Its TSDoc named an
  internal ticket in the middle of a sentence; the documentation site
  dropped that whole paragraph, and with it the default (the currency's
  minor units) and the rounding rule. The sentence now carries the rule
  without the ticket. No code changed.

## \[1.0.0\] — 2026-10-20

The first release. The entries below record how the content reached this
version; "breaking" there is relative to earlier, unreleased development
states.

### Changed (platform ADR-115)

- **Byte-identical checkout.** The package carries `.gitattributes` with
  `* -text`: Git converts no line end in it, so a checkout with
  `core.autocrlf=true` keeps the bytes its content hash names.
- `digitsOf` (an internal helper of the locale contract) is no longer
  exported from its module; it was never part of the package's public entry.

### Documented (2026-10-19) — runtime requirements

- `docs/API.md` § Runtime requirements and the README: `formatCurrency` with a `DecimalString` needs the ES2023 exact-decimal string form of `Intl.NumberFormat.prototype.format` (an older engine converts the string to a `Number` itself and loses precision **silently**); `formatElapsedDuration` needs `Intl.DurationFormat` and throws without it. Both on the server and in the browser; no polyfill is shipped. Checked on Node.js v26.7.0 and Chrome 155; first versions of other engines per MDN browser-compat-data, with a start-up check a host can run. No code change.

### Phase 2 of the reuse completion (2026-10-19, D28 to D31)

#### Added

- `NumberSpec` (`NumberNotation`, `NumberSign`): significant digits,
  scientific, engineering and compact notation and sign display for
  `formatNumber`; `sign` on `CurrencyFormatOptions`.
- `DecimalString`, `isDecimalString`, `toDecimalString`; `formatCurrency`
  formats a `DecimalString` amount exactly.
- `formatByteSize` with `ByteSizeOptions` (`system: 'decimal' | 'binary'`
  required, IEC symbols for binary).
- `formatUnit`, `MEASURE_UNITS`, `isMeasureUnit`, `MeasureUnit`,
  `SimpleMeasureUnit`, `UnitFormatOptions`: a measured quantity, never
  converted.
- `formatElapsedDuration` and its option types: an elapsed duration with an
  explicit input unit (requires `Intl.DurationFormat`).
- `formatList`, `ListFormatOptions`.
- `formatNumberRange`, `formatDateOnlyRange`.
- `LocalDateTimeString`, `LocalTimeString` with guards and constructors.
- Time-of-day input: `classifyTimeInput`, `getTimeInputPattern`,
  `formatLocalTimeForInput`, `assertTimeInputConstraints` and their types.

#### Changed

- **Breaking:** the date-only reader accepts only the whole form: a valid
  `YYYY-MM-DD` prefix with an invalid rest (`'2026-03-09Tgarbage'`) is
  unreadable, and `formatMachineDate` throws for it.
- `{decimals, maxDecimals}` and `PercentFormat` precision are validated
  (integers 0 to 100) with a `RangeError` naming the field.

#### Removed

- **Breaking:** `formatBytes`. Migrate `formatBytes(bytes, decimals)` to
  `formatByteSize(bytes, presentation, {system: 'binary', maxDecimals: decimals})`
  for the old 1024 scale; the label becomes `KiB`/`MiB` and the number follows
  the presentation.
- **Breaking:** `formatDocumentDate`, `formatDocumentGenerationDate`,
  `formatDocumentAmount` moved to `@workspace/pension-documents` (D28); a
  `NaN` amount now renders `''` there instead of `'NaN'`.
- `LocalDateTimeString`, `isLocalDateTimeString` and `toLocalDateTimeString`
  are no longer in `@workspace/active-types`; import them from here.

### First content

The first content of this package. The intended first release is 1.0.0; no
release is recorded yet.

### Added

- **The owner of formatting and parsing** (D26). One entry, the root, with
  every export that consumers previously imported from the `/formatters`
  subpath of a translation package: the presentation context and its types,
  the portable locale contract (`UnsupportedLocaleError`, `isSupportedLocale`,
  `normalizeDigits`), the calendar primitives (`getDateFnsLocale`,
  `getCalendarPhrases`), the date and number presets, human date, number,
  currency and percent formatting, recency, the date-only boundary, date and
  number input, machine formats and document formatting. Same names, same
  behaviour.
- `LocaleCode`, the open BCP 47 tag every formatter takes.
- `RecencyOptions`, the type of the third argument of `resolveRecency`
  (previously reachable only as a parameter type).
- `formatBytes`: a byte count in binary units with a fixed notation, moved
  unchanged from a utility package.
- **The vocabulary the public types are built on** (D27, platform ADR-114),
  moved unchanged from `@workspace/active-types`: the notation presets
  (`DATE_NOTATION_PRESETS`, `DATE_SHAPE_PRESETS`, `TIME_NOTATION_PRESETS`,
  `NUMBER_NOTATION_PRESETS`, `CURRENCY_DISPLAY_PRESETS`,
  `PRESENTATION_NOTATION_DIMENSIONS` and their types, `PresentationNotation`),
  the ISO date brands (`CalendarDateString`, `InstantString`, `IsoDateString`,
  their guards and constructors, `instantStringFromDate`) and the IANA zone
  brand (`IanaTimeZone`, `UTC_TIME_ZONE`, `isIanaTimeZone`, `toIanaTimeZone`,
  `canonicalizeTimeZone`, `listIanaTimeZones`). This package now depends on no
  workspace package.

### Migration

| Before | After |
| --- | --- |
| `import {…} from '@workspace/active-i18n/formatters'` | `import {…} from '@workspace/active-format'` |
| `import type {LocaleCode} from '@workspace/active-i18n'` | `import type {LocaleCode} from '@workspace/active-format'` |
| `import {formatBytes} from '@workspace/active-utils/formatters'` | `import {formatBytes} from '@workspace/active-format'` |
| the notation presets, ISO date brands and IANA zone brand from `@workspace/active-types` (root or a subpath) | `import {…} from '@workspace/active-format'` (D27) |

Declare `@workspace/active-format` as a dependency. Nothing else changes: no
symbol was renamed and no behaviour changed. A `vi.mock` that replaces
`@workspace/active-format` wholesale must keep the real module
(`importOriginal`), because the brands and presets now come from it.
