pond-ts 0.68.0 → 0.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +12 -3
- package/API.md +104 -100
- package/CHANGELOG.md +147 -1
- package/README.md +91 -9
- package/dist/batch/partitioned-time-series.d.ts +21 -5
- package/dist/core/calendar.d.ts +2 -5
- package/dist/core/calendar.js +4 -50
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +1 -0
- package/dist/core/time-zone.d.ts +122 -0
- package/dist/core/time-zone.js +413 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/sequence/sequence.d.ts +4 -1
- package/dist/sequence/sequence.js +15 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,21 +1,44 @@
|
|
|
1
1
|
# pond-ts
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/pond-ts)
|
|
4
|
+
[](https://github.com/pond-ts/pond/actions/workflows/ci.yml)
|
|
5
|
+
[](https://github.com/pond-ts/pond/blob/main/LICENSE)
|
|
6
|
+
[](https://pond-ts.org)
|
|
7
|
+
|
|
3
8
|
**Highly optimised, fully typed Timeseries library for TypeScript**
|
|
4
9
|
|
|
5
10
|
Schema-driven events, composable batch transforms, push-based streaming
|
|
6
|
-
ingest, multi-entity partitioning
|
|
7
|
-
|
|
11
|
+
ingest, multi-entity partitioning — and, optionally, React hooks and
|
|
12
|
+
canvas charts that read the series directly. All strict TypeScript end to
|
|
13
|
+
end, all immutable.
|
|
8
14
|
|
|
9
15
|
**pond-ts** is the TypeScript-first successor to
|
|
10
16
|
[pondjs](https://github.com/esnet/pond), rewritten from scratch with a
|
|
11
17
|
focus on type safety, composability, and the live-streaming patterns
|
|
12
18
|
that pondjs never grew.
|
|
13
19
|
|
|
20
|
+
## The packages
|
|
21
|
+
|
|
22
|
+
Three packages carry most projects. The core has no dependency on the other
|
|
23
|
+
two; add them only if you render.
|
|
24
|
+
|
|
25
|
+
| Package | What it is | Needs |
|
|
26
|
+
| --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
|
|
27
|
+
| **[`pond-ts`](https://www.npmjs.com/package/pond-ts)** — core | `TimeSeries` (batch) and `LiveSeries` (streaming) with one operator vocabulary: aggregate, rolling, align, fill, partition, join, typed columns. Node or browser, no React. | nothing |
|
|
28
|
+
| **[`@pond-ts/charts`](https://www.npmjs.com/package/@pond-ts/charts)** — optional | Declarative React charts on a canvas data plane that consume a pond series with no adapter: line, area, band, bar, scatter, box, candlestick, heat map; cursors, selection, pan/zoom, annotations. | `pond-ts`, `@pond-ts/react`, React 18/19 |
|
|
29
|
+
| **[`@pond-ts/react`](https://www.npmjs.com/package/@pond-ts/react)** — optional | Hooks to own a series in a component and read live views on a throttled snapshot cadence (`useLiveSeries`, `useSnapshot`, …). | `pond-ts`, React 18/19 |
|
|
30
|
+
|
|
14
31
|
```sh
|
|
15
|
-
npm install pond-ts
|
|
16
|
-
npm install @pond-ts/react
|
|
32
|
+
npm install pond-ts # core — enough for Node pipelines and non-React apps
|
|
33
|
+
npm install @pond-ts/charts @pond-ts/react pond-ts # add the React chart stack
|
|
17
34
|
```
|
|
18
35
|
|
|
36
|
+
Two domain packages ([`@pond-ts/financial`](#domain-packages) for markets,
|
|
37
|
+
[`@pond-ts/fit`](#domain-packages) for activity data) and one experimental
|
|
38
|
+
runtime ([`@pond-ts/process`](#domain-packages)) sit on top — see
|
|
39
|
+
[Domain packages](#domain-packages) below. All six release together under
|
|
40
|
+
one version; keep them in step.
|
|
41
|
+
|
|
19
42
|
- **Typed schemas** — declare once, every transform downstream narrows
|
|
20
43
|
off it. `event.get('cpu')` returns `number | undefined` straight from
|
|
21
44
|
the schema; no `as` casts.
|
|
@@ -108,6 +131,43 @@ The full live surface (`filter`, `map`, `select`, `window`, `aggregate`,
|
|
|
108
131
|
`sample`) is incremental — events flow, views emit, retention bounds
|
|
109
132
|
memory.
|
|
110
133
|
|
|
134
|
+
## Quick start: charts (React)
|
|
135
|
+
|
|
136
|
+
`@pond-ts/charts` reads a `TimeSeries` or `LiveSeries` directly — do the maths
|
|
137
|
+
in pond, hand the result to a layer. Rows share one x scale, so they pan,
|
|
138
|
+
zoom and track the cursor together.
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
import {
|
|
142
|
+
BandChart,
|
|
143
|
+
ChartContainer,
|
|
144
|
+
ChartRow,
|
|
145
|
+
Layers,
|
|
146
|
+
LineChart,
|
|
147
|
+
YAxis,
|
|
148
|
+
} from '@pond-ts/charts';
|
|
149
|
+
|
|
150
|
+
// `bands` is the baseline() result from the batch quick start:
|
|
151
|
+
// cpu + avg / sd / upper / lower columns.
|
|
152
|
+
export function CpuChart({ width }: { width: number }) {
|
|
153
|
+
return (
|
|
154
|
+
<ChartContainer width={width} cursor="crosshair" panZoom>
|
|
155
|
+
<ChartRow height={240}>
|
|
156
|
+
<YAxis id="cpu" format=".0%" />
|
|
157
|
+
<Layers>
|
|
158
|
+
<BandChart series={bands} lower="lower" upper="upper" axis="cpu" />
|
|
159
|
+
<LineChart series={bands} column="cpu" axis="cpu" />
|
|
160
|
+
</Layers>
|
|
161
|
+
</ChartRow>
|
|
162
|
+
</ChartContainer>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Pass `width="auto"` to measure the parent instead. Live data renders through
|
|
168
|
+
the same layers: own the series with `useLiveSeries` from `@pond-ts/react`
|
|
169
|
+
and pass its snapshot as `series`.
|
|
170
|
+
|
|
111
171
|
## Quick start: multi-entity
|
|
112
172
|
|
|
113
173
|
`partitionBy` routes events into per-key buffers. Every stateful
|
|
@@ -182,6 +242,26 @@ it is behind. Run locally:
|
|
|
182
242
|
npm run build && node packages/core/bench/vs-pondjs.cjs
|
|
183
243
|
```
|
|
184
244
|
|
|
245
|
+
## Domain packages
|
|
246
|
+
|
|
247
|
+
Optional, domain-specific, all on plain pond series:
|
|
248
|
+
|
|
249
|
+
- **[`@pond-ts/financial`](https://www.npmjs.com/package/@pond-ts/financial)**
|
|
250
|
+
— sixty-plus oracle-verified technical studies (SMA, EMA, RSI, MACD,
|
|
251
|
+
Bollinger, ATR, VWAP, …) that append columns to a bar series, a fluent
|
|
252
|
+
`bars.sma({ period: 20 }).rsi({ period: 14 })` form, and a
|
|
253
|
+
`TradingCalendar` so session-aligned bars, rolling windows and chart axes
|
|
254
|
+
stop at the close.
|
|
255
|
+
- **[`@pond-ts/fit`](https://www.npmjs.com/package/@pond-ts/fit)** — fitness
|
|
256
|
+
and activity analytics: typed quantities with units, canonical activity
|
|
257
|
+
series, geo (distance, elevation, best efforts), power (NP / IF / TSS,
|
|
258
|
+
curves), heart-rate zones, splits.
|
|
259
|
+
- **[`@pond-ts/process`](https://www.npmjs.com/package/@pond-ts/process)** —
|
|
260
|
+
**experimental.** Computations as data: processing graphs authored fluently
|
|
261
|
+
or composed as JSON, resolved against a declared op vocabulary with
|
|
262
|
+
content-addressed caching, provenance and per-node timings. The API is
|
|
263
|
+
expected to move.
|
|
264
|
+
|
|
185
265
|
## Documentation
|
|
186
266
|
|
|
187
267
|
The full guide is at **<https://pond-ts.org/>**.
|
|
@@ -233,20 +313,22 @@ the loop:
|
|
|
233
313
|
|
|
234
314
|
## Develop
|
|
235
315
|
|
|
236
|
-
The repo is an npm-workspaces monorepo with
|
|
237
|
-
(`pond-ts`, `@pond-ts/react
|
|
316
|
+
The repo is an npm-workspaces monorepo with six published packages
|
|
317
|
+
(`pond-ts`, `@pond-ts/react`, `@pond-ts/charts`, `@pond-ts/financial`,
|
|
318
|
+
`@pond-ts/fit`, `@pond-ts/process`). Node 18+ for runtime; Node 20+ for the
|
|
238
319
|
docs site (Docusaurus).
|
|
239
320
|
|
|
240
321
|
```sh
|
|
241
|
-
npm install # one-time, hoists deps for
|
|
322
|
+
npm install # one-time, hoists deps for all packages
|
|
242
323
|
npm run build # build both packages
|
|
243
324
|
npm test # runtime + type-level tests on both packages
|
|
244
325
|
npm run format # prettier write across the repo
|
|
245
326
|
npm run verify # format check + build + test (CI parity)
|
|
246
327
|
```
|
|
247
328
|
|
|
248
|
-
`packages
|
|
249
|
-
|
|
329
|
+
Each package lives under `packages/<name>/` (`core` is `pond-ts`, the rest
|
|
330
|
+
match their scoped names). Docs live in `website/` — its own npm root, not a
|
|
331
|
+
workspace.
|
|
250
332
|
|
|
251
333
|
## License
|
|
252
334
|
|
|
@@ -4,7 +4,7 @@ import { Sequence } from '../sequence/sequence.js';
|
|
|
4
4
|
import type { DurationInput } from '../core/duration.js';
|
|
5
5
|
import type { TemporalLike } from '../core/temporal.js';
|
|
6
6
|
import type { BatchSampleStrategy } from '../sequence/sample.js';
|
|
7
|
-
import type { AggregateSchema, AlignSchema, AppendColumn, BaselineSchema, DedupeKeep, DiffSchema, EventDataForSchema, FillMapping, FillStrategy, MaterializeSchema, NumericColumnNameForSchema, RollingAlignment, RollingSchema, SeriesSchema, SmoothAppendSchema, SmoothMethod, SmoothSchema, ValidatedAggregateMap } from '../schema/index.js';
|
|
7
|
+
import type { AggregateSchema, AlignSchema, AppendColumn, BaselineSchema, DedupeKeep, DiffSchema, EventDataForSchema, ValueColumnsForSchema, FillMapping, FillStrategy, MaterializeSchema, NumericColumnNameForSchema, RollingAlignment, RollingSchema, SeriesSchema, SmoothAppendSchema, SmoothMethod, SmoothSchema, ValidatedAggregateMap } from '../schema/index.js';
|
|
8
8
|
import type { ScanStep } from './operators/scan.js';
|
|
9
9
|
type SequenceLike = Sequence | BoundedSequence;
|
|
10
10
|
type AlignMethod = 'hold' | 'linear';
|
|
@@ -24,7 +24,7 @@ type AlignSample = 'begin' | 'center' | 'end';
|
|
|
24
24
|
* the one actually passed — harmless because injected columns are already
|
|
25
25
|
* optional.
|
|
26
26
|
*/
|
|
27
|
-
export type WithPartitionColumns<Mapping, By extends string> = string extends By ? Mapping : Mapping & {
|
|
27
|
+
export type WithPartitionColumns<S extends SeriesSchema, Mapping, By extends string> = string extends By ? Mapping : string extends ValueColumnsForSchema<S>[number]['name'] ? Mapping : Mapping & {
|
|
28
28
|
readonly [C in Exclude<By, keyof Mapping>]: 'first';
|
|
29
29
|
};
|
|
30
30
|
/**
|
|
@@ -74,6 +74,22 @@ export declare class PartitionedTimeSeries<S extends SeriesSchema, K extends str
|
|
|
74
74
|
#private;
|
|
75
75
|
readonly source: TimeSeries<S>;
|
|
76
76
|
readonly by: ReadonlyArray<keyof EventDataForSchema<S> & string>;
|
|
77
|
+
/**
|
|
78
|
+
* Phantom, erased at runtime. Pins `By` **contravariantly** so a view
|
|
79
|
+
* partitioned by one column cannot be assigned where a view partitioned
|
|
80
|
+
* by another is claimed (`PartitionedTimeSeries<S, K, 'host'>` ←
|
|
81
|
+
* `partitionBy('region')` is an error), while a specialised view still
|
|
82
|
+
* assigns to the legacy `PartitionedTimeSeries<S>` / `<S, K>` shape.
|
|
83
|
+
* Without it `By` only appears inside a conditional in return positions
|
|
84
|
+
* and TypeScript treats it as freely convertible (Codex finding on #724).
|
|
85
|
+
*
|
|
86
|
+
* Spelling note: **`never` (the default) is the "any / unknown column"
|
|
87
|
+
* view**, and it is the top of this pin — every specialised view assigns
|
|
88
|
+
* to it. `string` is the *bottom* (a `string`-typed `By` assigns to any
|
|
89
|
+
* literal), so do not write `PartitionedTimeSeries<S, K, string>` to mean
|
|
90
|
+
* "any column"; the `partitionBy` overloads never produce it.
|
|
91
|
+
*/
|
|
92
|
+
readonly __partitionColumns?: (by: By) => void;
|
|
77
93
|
/**
|
|
78
94
|
* Declared partition values when `partitionBy(col, { groups })` was
|
|
79
95
|
* used. When set, `toMap` iterates in declared order (not insertion
|
|
@@ -266,13 +282,13 @@ export declare class PartitionedTimeSeries<S extends SeriesSchema, K extends str
|
|
|
266
282
|
rolling<const Mapping extends ValidatedAggregateMap<S, Mapping>>(window: DurationInput, mapping: Mapping, options?: {
|
|
267
283
|
alignment?: RollingAlignment;
|
|
268
284
|
minSamples?: number;
|
|
269
|
-
}): PartitionedTimeSeries<RollingSchema<S, WithPartitionColumns<Mapping, By>>, K, By>;
|
|
285
|
+
}): PartitionedTimeSeries<RollingSchema<S, WithPartitionColumns<S, Mapping, By>>, K, By>;
|
|
270
286
|
rolling<const Mapping extends ValidatedAggregateMap<S, Mapping>>(sequence: SequenceLike, window: DurationInput, mapping: Mapping, options?: {
|
|
271
287
|
alignment?: RollingAlignment;
|
|
272
288
|
sample?: AlignSample;
|
|
273
289
|
range?: TemporalLike;
|
|
274
290
|
minSamples?: number;
|
|
275
|
-
}): PartitionedTimeSeries<AggregateSchema<S, WithPartitionColumns<Mapping, By>>, K, By>;
|
|
291
|
+
}): PartitionedTimeSeries<AggregateSchema<S, WithPartitionColumns<S, Mapping, By>>, K, By>;
|
|
276
292
|
/** Per-partition `smooth`. See {@link TimeSeries.smooth}. */
|
|
277
293
|
smooth<const Target extends NumericColumnNameForSchema<S>, const Output extends string | undefined = undefined>(column: Target, method: SmoothMethod, options: {
|
|
278
294
|
alpha: number;
|
|
@@ -332,7 +348,7 @@ export declare class PartitionedTimeSeries<S extends SeriesSchema, K extends str
|
|
|
332
348
|
/** Per-partition `aggregate`. See {@link TimeSeries.aggregate}. */
|
|
333
349
|
aggregate<const Mapping extends ValidatedAggregateMap<S, Mapping>>(sequence: SequenceLike, mapping: Mapping, options?: {
|
|
334
350
|
range?: TemporalLike;
|
|
335
|
-
}): PartitionedTimeSeries<AggregateSchema<S, WithPartitionColumns<Mapping, By>>, K, By>;
|
|
351
|
+
}): PartitionedTimeSeries<AggregateSchema<S, WithPartitionColumns<S, Mapping, By>>, K, By>;
|
|
336
352
|
}
|
|
337
353
|
export {};
|
|
338
354
|
//# sourceMappingURL=partitioned-time-series.d.ts.map
|
package/dist/core/calendar.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export type CalendarUnit = 'day' | 'week' | 'month';
|
|
1
|
+
/** A calendar bucket unit. Boundaries are wall-clock in an IANA zone, so a `'day'` is 23, 24 or 25 hours across DST. */
|
|
2
|
+
export type CalendarUnit = 'day' | 'week' | 'month' | 'quarter' | 'year';
|
|
3
3
|
export type WeekStartsOn = 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
|
4
4
|
export type TimeZoneOptions = {
|
|
5
5
|
timeZone?: string;
|
|
@@ -10,9 +10,6 @@ export type CalendarOptions = TimeZoneOptions & {
|
|
|
10
10
|
export declare function resolveTimeZone(options?: TimeZoneOptions): string;
|
|
11
11
|
export declare function normalizeWeekStartsOn(value: number | undefined): WeekStartsOn;
|
|
12
12
|
export declare function parseTimestampString(value: string, options?: TimeZoneOptions): number;
|
|
13
|
-
export declare function toPlainDateStart(instantMs: number, timeZone: string, unit: CalendarUnit, weekStartsOn: WeekStartsOn): Temporal.PlainDate;
|
|
14
|
-
export declare function plainDateToStart(date: Temporal.PlainDate, timeZone: string): Temporal.ZonedDateTime;
|
|
15
|
-
export declare function nextCalendarStart(current: Temporal.PlainDate, unit: CalendarUnit): Temporal.PlainDate;
|
|
16
13
|
export declare function dayRangeForDate(reference: string, options?: TimeZoneOptions): {
|
|
17
14
|
start: number;
|
|
18
15
|
end: number;
|
package/dist/core/calendar.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Temporal } from '@js-temporal/polyfill';
|
|
2
|
+
import { TimeZone } from './time-zone.js';
|
|
2
3
|
const DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
3
4
|
const YEAR_MONTH_RE = /^\d{4}-\d{2}$/;
|
|
4
5
|
const DATE_TIME_LOCAL_RE = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?$/;
|
|
@@ -42,51 +43,6 @@ export function parseTimestampString(value, options = {}) {
|
|
|
42
43
|
}
|
|
43
44
|
return Temporal.Instant.from(value).epochMilliseconds;
|
|
44
45
|
}
|
|
45
|
-
export function toPlainDateStart(instantMs, timeZone, unit, weekStartsOn) {
|
|
46
|
-
// **Floor to the containing millisecond.** `Temporal.Instant` refuses a
|
|
47
|
-
// fractional epoch ms outright — `fromEpochMilliseconds(1577836800000.37)`
|
|
48
|
-
// throws `epoch milliseconds must be an integer` — and a fraction is not a
|
|
49
|
-
// caller error here. A chart's wheel-zoom derives its view range from pixel
|
|
50
|
-
// positions through `xScale.invert()`, so a perfectly ordinary gesture hands
|
|
51
|
-
// us `1.7e12 + 0.37`; realizing a calendar sequence over that range then
|
|
52
|
-
// crashed the page outright.
|
|
53
|
-
//
|
|
54
|
-
// Flooring is the only sane reading rather than a papering-over: the epoch
|
|
55
|
-
// millisecond *is* the atomic unit of this model, so an over-precise input
|
|
56
|
-
// can only mean the millisecond containing it, and calendar boundaries are
|
|
57
|
-
// themselves whole milliseconds — so the bucket containing `t` and the one
|
|
58
|
-
// containing `t + 0.37` are necessarily the same. Integer inputs are
|
|
59
|
-
// untouched.
|
|
60
|
-
//
|
|
61
|
-
// `Math.floor`, not `Math.trunc`: before 1970 they disagree, and `-5.5` lies
|
|
62
|
-
// inside the millisecond spanning `[-6, -5)`, which is `-6`.
|
|
63
|
-
const zoned = Temporal.Instant.fromEpochMilliseconds(Math.floor(instantMs)).toZonedDateTimeISO(timeZone);
|
|
64
|
-
const date = zoned.toPlainDate();
|
|
65
|
-
if (unit === 'day') {
|
|
66
|
-
return date;
|
|
67
|
-
}
|
|
68
|
-
if (unit === 'month') {
|
|
69
|
-
return Temporal.PlainDate.from({
|
|
70
|
-
year: date.year,
|
|
71
|
-
month: date.month,
|
|
72
|
-
day: 1,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
const offset = (date.dayOfWeek - weekStartsOn + 7) % 7;
|
|
76
|
-
return date.subtract({ days: offset });
|
|
77
|
-
}
|
|
78
|
-
export function plainDateToStart(date, timeZone) {
|
|
79
|
-
return date.toZonedDateTime({ timeZone }).startOfDay();
|
|
80
|
-
}
|
|
81
|
-
export function nextCalendarStart(current, unit) {
|
|
82
|
-
if (unit === 'day') {
|
|
83
|
-
return current.add({ days: 1 });
|
|
84
|
-
}
|
|
85
|
-
if (unit === 'week') {
|
|
86
|
-
return current.add({ weeks: 1 });
|
|
87
|
-
}
|
|
88
|
-
return current.add({ months: 1 });
|
|
89
|
-
}
|
|
90
46
|
export function dayRangeForDate(reference, options = {}) {
|
|
91
47
|
const timeZone = resolveTimeZone(options);
|
|
92
48
|
const start = Temporal.PlainDate.from(reference)
|
|
@@ -102,12 +58,10 @@ export function calendarRangeForReference(unit, reference, options = {}) {
|
|
|
102
58
|
const timeZone = resolveTimeZone(options);
|
|
103
59
|
const weekStartsOn = normalizeWeekStartsOn(options.weekStartsOn);
|
|
104
60
|
const referenceMs = parseTimestampString(reference, { timeZone });
|
|
105
|
-
const
|
|
106
|
-
const start = plainDateToStart(startDate, timeZone);
|
|
107
|
-
const end = plainDateToStart(nextCalendarStart(startDate, unit), timeZone);
|
|
61
|
+
const zone = TimeZone.of(timeZone);
|
|
108
62
|
return {
|
|
109
|
-
start:
|
|
110
|
-
end:
|
|
63
|
+
start: zone.startOf(unit, referenceMs, { weekStartsOn }),
|
|
64
|
+
end: zone.next(unit, referenceMs, { weekStartsOn }),
|
|
111
65
|
};
|
|
112
66
|
}
|
|
113
67
|
//# sourceMappingURL=calendar.js.map
|
package/dist/core/index.d.ts
CHANGED
|
@@ -6,4 +6,6 @@ export type { DurationInput, DurationUnit } from './duration.js';
|
|
|
6
6
|
export { ValidationError } from './errors.js';
|
|
7
7
|
export type { EventKey, IntervalInput, IntervalValue, TemporalLike, TimeRangeInput, TimestampInput, } from './temporal.js';
|
|
8
8
|
export type { CalendarOptions, CalendarUnit, TimeZoneOptions, } from './calendar.js';
|
|
9
|
+
export { TimeZone } from './time-zone.js';
|
|
10
|
+
export type { Disambiguation, StartOfOptions, ZonedParts, ZonedPartsInput, } from './time-zone.js';
|
|
9
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/core/index.js
CHANGED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { CalendarUnit, WeekStartsOn } from './calendar.js';
|
|
2
|
+
/**
|
|
3
|
+
* How `TimeZone.instant()` resolves a wall-clock time that a transition
|
|
4
|
+
* makes ambiguous (a fall-back repeats an hour) or skips (a spring-forward
|
|
5
|
+
* drops one). Same vocabulary and same defaults as Temporal:
|
|
6
|
+
*
|
|
7
|
+
* - `'compatible'` (default) — the earlier instant when the time repeats,
|
|
8
|
+
* the instant *after* the gap when it is skipped (02:30 on a spring-forward
|
|
9
|
+
* night becomes 03:30). This is also what `startOf('day')` needs on the
|
|
10
|
+
* rare days that have no midnight.
|
|
11
|
+
* - `'earlier'` / `'later'` — always the earlier / later of the two readings.
|
|
12
|
+
* - `'reject'` — throw a `RangeError` for either case.
|
|
13
|
+
*/
|
|
14
|
+
export type Disambiguation = 'compatible' | 'earlier' | 'later' | 'reject';
|
|
15
|
+
/** The wall-clock reading of an instant in a zone. `weekday` is ISO: 1 = Monday … 7 = Sunday. */
|
|
16
|
+
export type ZonedParts = {
|
|
17
|
+
year: number;
|
|
18
|
+
month: number;
|
|
19
|
+
day: number;
|
|
20
|
+
hour: number;
|
|
21
|
+
minute: number;
|
|
22
|
+
second: number;
|
|
23
|
+
millisecond: number;
|
|
24
|
+
weekday: 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
|
25
|
+
};
|
|
26
|
+
/** The date-and-time fields `TimeZone.instant()` accepts. Time fields default to zero. */
|
|
27
|
+
export type ZonedPartsInput = {
|
|
28
|
+
year: number;
|
|
29
|
+
month: number;
|
|
30
|
+
day: number;
|
|
31
|
+
hour?: number;
|
|
32
|
+
minute?: number;
|
|
33
|
+
second?: number;
|
|
34
|
+
millisecond?: number;
|
|
35
|
+
};
|
|
36
|
+
export type StartOfOptions = {
|
|
37
|
+
/** First day of the week for `'week'`, ISO numbering (1 = Monday, default) … 7 = Sunday. */
|
|
38
|
+
weekStartsOn?: WeekStartsOn;
|
|
39
|
+
};
|
|
40
|
+
declare function assertCalendarUnit(unit: string): asserts unit is CalendarUnit;
|
|
41
|
+
/**
|
|
42
|
+
* An IANA time zone as a calendar: the one place in pond that turns instants
|
|
43
|
+
* (UTC epoch milliseconds) into wall-clock readings and calendar boundaries,
|
|
44
|
+
* and back.
|
|
45
|
+
*
|
|
46
|
+
* Instances are interned — `TimeZone.of('Europe/Berlin')` returns the same
|
|
47
|
+
* object every time — and cache the zone's offset transitions as they are
|
|
48
|
+
* discovered, so after the first query in a stretch of history every call
|
|
49
|
+
* is integer arithmetic. `Sequence.calendar` buckets with it; the charts'
|
|
50
|
+
* time axis places and labels ticks with it; the two therefore agree on
|
|
51
|
+
* every boundary by construction.
|
|
52
|
+
*
|
|
53
|
+
* A `TimeZone` holds no instant. Values (`Time`, `TimeRange`, `Interval`)
|
|
54
|
+
* stay plain UTC milliseconds; the zone is a parameter to the code that
|
|
55
|
+
* interprets them.
|
|
56
|
+
*/
|
|
57
|
+
export declare class TimeZone {
|
|
58
|
+
#private;
|
|
59
|
+
/** The canonical IANA identifier, e.g. `'America/New_York'` or `'UTC'`. */
|
|
60
|
+
readonly id: string;
|
|
61
|
+
private constructor();
|
|
62
|
+
/**
|
|
63
|
+
* Example: `TimeZone.of('Australia/Sydney')`. Looks up a zone by IANA
|
|
64
|
+
* identifier. Throws `RangeError` for an identifier the runtime does not
|
|
65
|
+
* know. Case-insensitive on input; `id` reports the canonical spelling.
|
|
66
|
+
* A fixed-offset identifier such as `'+05:30'` is accepted too, as
|
|
67
|
+
* Temporal accepts it, and behaves as a zone with a single segment.
|
|
68
|
+
*/
|
|
69
|
+
static of(id: string): TimeZone;
|
|
70
|
+
/** Example: `TimeZone.UTC.startOf('month', t)`. The UTC zone. */
|
|
71
|
+
static get UTC(): TimeZone;
|
|
72
|
+
/**
|
|
73
|
+
* Example: `TimeZone.local()`. The runtime's own zone, as the environment
|
|
74
|
+
* reports it. Resolved on every call, so a test that changes `TZ` between
|
|
75
|
+
* calls sees the change.
|
|
76
|
+
*/
|
|
77
|
+
static local(): TimeZone;
|
|
78
|
+
/** Example: `zone.offsetAt(t)`. The zone's UTC offset at an instant, in milliseconds east of UTC. */
|
|
79
|
+
offsetAt(ms: number): number;
|
|
80
|
+
/**
|
|
81
|
+
* Example: `zone.parts(t).hour`. The wall-clock reading of an instant in
|
|
82
|
+
* this zone.
|
|
83
|
+
*/
|
|
84
|
+
parts(ms: number): ZonedParts;
|
|
85
|
+
/**
|
|
86
|
+
* Example: `zone.instant({ year: 2026, month: 3, day: 29, hour: 2, minute: 30 })`.
|
|
87
|
+
* The instant at which this zone's clocks read the given wall time. When
|
|
88
|
+
* a transition makes the reading ambiguous or nonexistent,
|
|
89
|
+
* `disambiguation` decides (default `'compatible'`, as Temporal).
|
|
90
|
+
*/
|
|
91
|
+
instant(parts: ZonedPartsInput, options?: {
|
|
92
|
+
disambiguation?: Disambiguation;
|
|
93
|
+
}): number;
|
|
94
|
+
/**
|
|
95
|
+
* Example: `zone.startOf('week', t, { weekStartsOn: 7 })`. The first
|
|
96
|
+
* instant of the calendar unit containing `ms`, in this zone. On a day
|
|
97
|
+
* with no midnight (a spring-forward at 00:00) this is the first instant
|
|
98
|
+
* that exists, as `Temporal.ZonedDateTime.startOfDay` does.
|
|
99
|
+
*/
|
|
100
|
+
startOf(unit: CalendarUnit, ms: number, options?: StartOfOptions): number;
|
|
101
|
+
/**
|
|
102
|
+
* Example: `zone.next('month', t)`. The first instant of the calendar unit
|
|
103
|
+
* *after* the one containing `ms` — i.e. the exclusive end of `startOf`'s
|
|
104
|
+
* bucket.
|
|
105
|
+
*/
|
|
106
|
+
next(unit: CalendarUnit, ms: number, options?: StartOfOptions): number;
|
|
107
|
+
/**
|
|
108
|
+
* Example: `zone.abbreviation(t)` → `'EDT'`. The zone's short name at an
|
|
109
|
+
* instant, as `Intl` reports it for `locale` (default: the runtime's
|
|
110
|
+
* locale). Which zones have a conventional abbreviation is a locale
|
|
111
|
+
* question — `en-US` knows `EST`, `en-AU` knows `AEDT`, and neither knows
|
|
112
|
+
* the other's; the fallback is a `GMT±h[:mm]` offset string. Pass the
|
|
113
|
+
* viewer's locale when rendering.
|
|
114
|
+
*/
|
|
115
|
+
abbreviation(ms: number, options?: {
|
|
116
|
+
locale?: string;
|
|
117
|
+
}): string;
|
|
118
|
+
toString(): string;
|
|
119
|
+
toJSON(): string;
|
|
120
|
+
}
|
|
121
|
+
export { assertCalendarUnit };
|
|
122
|
+
//# sourceMappingURL=time-zone.d.ts.map
|