GrDuration
Overview
When to take it
- how long it took — the duration of a call, the time of a build, the downtime of equipment: “2 h 30 min” reads faster than “9000”;
- how long it has been running right now — pass the moment of the start as a single date, and the label becomes live: the timer is shared across the whole application and is removed on a hidden tab;
- the interval between two moments — a pair of dates is computed by itself, and there is no need to subtract milliseconds by hand;
- the value travels into the markup —
datetimeis filled with the exact length in ISO 8601, even when the text has been shortened to two units.
When to take something else
| Need | Take |
|---|---|
| Show how long ago it was | GrRelativeTime |
| Choose a moment rather than show a length | GrDatePicker / GrTimePicker |
| Enter a duration rather than show it | GrNumberInput |
| Show the share of what has elapsed out of the whole | GrProgressBar |
Examples 3 each with a live demo and its code
How long the pipeline took
Each run is a pair of
Dates as the CI API returns them — a measured interval, no subtracting milliseconds by hand.max-units="2"withwidth="narrow"reads «23m 29s» and drops the rest rather than rounding up. The default slot keeps the text and draws a bar against the slowest run, while the<time>around it still carries the exact length in ISO 8601.billing-service · pipeline runsToday · the budget for main is 15 minutes - #4182 · mainpasseda96c453
- #4181 · feat/sepa-instantfailed13b92a7
- #4180 · mainpassed3a71377
- #4179 · fix/dunning-localepassedca5d8d1
A call that is still going
One date is the moment the call started: with
livethe label counts up to «now» on a shared timer, ticking every second only because seconds are shown. Ending the call hands over a pair of dates — the same component, a fixed length. The history below is numbers in seconds, kept coarse withsmallest-unit="minute".AROn call · Ana RibeiroRefund for INV-0419 · +351 912 004 118Earlier todayAverage- Ben HartleyVAT number on invoices
- Chloé MoreauCard declined on renewal
- Diego GarcíaSeats after a downgrade
The phases of an outage
An outage longer than a day is still counted in hours by the people who lived through it:
largest-unit="hour"keeps «27 hr, 15 min» instead of «1 day, 3 hr». The notice for customers is prose, so units get full names withwidth="long", and each status page, English and German, names its language withlocalewhatever the language of the admin around it. There the start date is measured againstbaserather than the clock, so the text is the same on the server and in the browser.INC-2291 · card and SEPA payments degradedPost-mortem · 28–30 September - Detectionfrom the first failed charge to the page
- Mitigationcard payments routed to the backup provider
- RecoverySEPA backlog re-sent and reconciled
- Total
Status page · English Card payments were unavailable for ; no charge was lost.
Status page · German Kartenzahlungen waren lang nicht verfügbar; keine Zahlung ging verloren.
API generated from the package · cannot drift
Props
| Prop | Type | default | Description |
|---|---|---|---|
locale | string | undefined | undefined | Display locale. Not set — from the application's i18n adapter. |
value | number | Date | readonly [Date, Date] | null | undefined | undefined | What to measure. Three forms, each distinguishable by type: - **a number** — seconds; - **a pair of dates** — the span between them; - **a single date** — from it up to "now"; such a label is live and ticks. |
base | Date | undefined | undefined | What to compare against instead of "now" — for the single-date form. When set, the clock is not read at all: no timer, no divergence between server and client rendering. The same makes tests and snapshots reproducible. |
live | boolean | undefined | undefined | Update live. The component picks the tick itself from the smallest unit shown. |
maxUnits | number | undefined | undefined | How many units to show in a row: `2` gives "2 h 30 min". |
largestUnit | DurationUnit | undefined | undefined | Do not split above this unit: the remainder accumulates in it. |
smallestUnit | DurationUnit | undefined | undefined | Do not go below this one. |
width | NameWidth | undefined | undefined | Length of the unit names: "2 hours 30 minutes" versus "2 hr 30 min". |
Slots
| Slot | Type | Description |
|---|---|---|
default | { text: string; datetime: string; seconds: number; } | Custom markup instead of the text: the same values the component renders itself. |
Types
Every exported type of the subpath, grouped by the file it lives in. Names, generics and bodies come from the package’s declaration files and cannot drift.
import type { GrDurationConfigurableProps, GrDurationProps } from '@feugene/granularity-chrono/components/GrDuration'Filedist/types/components/GrDuration/config.d.ts
const grDurationConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrDuration">;Filedist/types/components/GrDuration/defaults.d.ts
interface GrDurationConfigurableProps {
width: NameWidth;
maxUnits: number;
largestUnit: DurationUnit;
smallestUnit: DurationUnit;
live: boolean;
}Filedist/types/components/GrDuration/safelist.d.ts
const grDurationSafelist: string[];Filedist/types/components/GrDuration/GrDuration.vue.d.ts
interface GrDurationProps {
value?: number | Date | readonly [Date, Date] | null;
base?: Date;
live?: boolean;
maxUnits?: number;
largestUnit?: DurationUnit;
smallestUnit?: DurationUnit;
width?: NameWidth;
locale?: string;
}Usage from the library prose
There are four units, and there will be nothing larger
Days, hours, minutes, seconds. Months and years are deliberately not here: they are calendar ones —
of different lengths in February and in July — and they cannot be derived from a number of seconds
without lying. A gap that really is measured by the calendar is shown by
GrRelativeTime, and computed by differenceInMonths.
A ceiling rather than a quota
maxUnits limits the number of units from above and adds nothing: exactly two hours is “2 h” rather
than “2 h 0 min”. The smaller part is discarded rather than rounded — “2 h 59 min 30 s” stays
“2 h 59 min”. Rounding would raise the display above the time that really has elapsed, and this value
is usually used to measure precisely that.
Zero is the only exception to the discarding: “0 s” is printed, because an empty string reads as “there is no data”, and a zero means something else.
A live label belongs only to the form with a single date
A number and a pair of dates set the length as a whole, and there is nothing in them to tick. The moment of the start is another matter: until “now” the time keeps running, and the label recomputes itself. The tick is chosen by the smallest unit shown, so a label in hours does not wake the tab every second.
The live display is derived from the clock, which means the server render and the client one will
diverge. The component marks that with data-allow-mismatch, and the mark is removed not by a flag
but by data: pass base and the render becomes deterministic.
Limits
There is no countdown here: “2 h 30 min left” is the same length, but a deadline, a zero and the transition into negative values belong to a scenario rather than to a label. Compute the remainder yourself and pass it as a number.
Props in this example