/** How a period is cut into buckets, and the one rule for charts over dated rows: the buckets partition the * window, starting on its first day, so they add up to its figure. The bucket holding now and one cut by * the period's edge are partial, and beside finished ones read as a collapse; they are marked, never * dropped unsaid. */ export type BucketUnit = "day" | "week" | "month"; export interface Bucket { start: Date; end: Date; /** Holds now or runs past the edge: not a whole figure. */ partial: boolean; } export declare const startOfDay: (date: Date) => Date; export declare function daySpan(start: Date, end: Date): number; export declare function dayAfter(start: Date, days: number): Date; /** * The unit that cuts a window into about twelve periods at most, so a sparse count reads as a shape rather * than a comb of single days: a fortnight by day, a month to a quarter by week, longer by month. */ export declare function bucketUnit(start: Date, end: Date): BucketUnit; /** * Where a window's first period starts: a day or a week on the window's own first day, so its periods * partition it and add up to its figure (a month's weeks run 01–07, 08–14…); a month on the calendar * month holding it. */ export declare function periodStart(date: Date, unit: BucketUnit): Date; /** Anchored on the window's start (`periodStart`). Partial when holding now or cut by the edge; buckets * starting after now are not returned. */ export declare function bucketsOf(start: Date, end: Date, now: Date, unit?: BucketUnit): Bucket[]; /** `YYYY-MM-DD`, with or without a time. */ export declare function parseWhen(value: string | null | undefined): Date | null; export declare function sumByBucket(rows: readonly T[], when: (row: T) => string | null | undefined, value: (row: T) => number | null | undefined, buckets: readonly Bucket[]): number[]; /** Both ends inclusive, whole days. */ export declare function inPeriod(value: string | null | undefined, start: Date, end: Date): boolean; /** `null` when the base is zero. */ export declare function percentChange(current: number, previous: number): number | null; export interface TrendPoint { /** What a chart labels the point by. */ start: Date; value: number; } export interface TrendSeries { unit: BucketUnit; /** A running or cut bucket is not among them. */ points: readonly TrendPoint[]; /** A bucket still filling or cut by the edge was left out. */ partial: boolean; /** The bucket holding now, summed so far: drawn marked as running, never beside the points as a peer. */ running: TrendPoint | null; } /** One definition for both readings of a period — a trend chart and a register band's change — so they * agree on which buckets count. */ export declare function trendBuckets(rows: readonly T[], window: { start: Date; end: Date; now: Date; }, when: (row: T) => string | null | undefined, value: (row: T) => number | null | undefined): TrendSeries; /** The later half of the buckets against the earlier, as a percentage; nothing without a base. Halves, not * the last bucket, since day-on-day is noise; per bucket, since an odd count would read as growth. */ export declare function seriesChange(points: readonly TrendPoint[]): number | null;