/**
* Shared date/time format tokens (date-fns syntax).
*
* These are the canonical formats used across the EthisysCore monolith and
* plugins. Change a value here for a global locale requirement rather than
* hardcoding a format string at a call site.
*/
/** ISO wire format `yyyy-MM-dd` — the standard date-only format throughout the app. */
declare const DATE_FORMAT = "yyyy-MM-dd";
/** Audit-log timestamp, e.g. `5 March 2026, 14:30`. */
declare const AUDIT_DATE_FORMAT = "d MMMM yyyy, HH:mm";
/** User-facing date display, e.g. `5 Mar 2026`. */
declare const DISPLAY_DATE_FORMAT = "d MMM yyyy";
/** Weekday + day + month, e.g. `Monday, 5 March`. */
declare const DAY_DATE_FORMAT = "EEEE, d MMMM";
/** Abbreviated day + month, e.g. `Mar 5`. */
declare const DAY_MONTH_FORMAT = "MMM d";
/** Abbreviated day + month + year, e.g. `Mar 5, 2026`. */
declare const DAY_MONTH_YEAR_FORMAT = "MMM d, yyyy";
/** 12-hour time, e.g. `2:30 PM`. */
declare const TIME_FORMAT = "h:mm a";
/** Short datetime, e.g. `Mar 5, 2:30 PM`. */
declare const SHORT_DATETIME_FORMAT = "MMM d, h:mm a";
/** Milliseconds in a day — whole-day duration / diff math (`daysBetweenIso`, axis geometry). */
declare const MS_PER_DAY = 86400000;
/** Milliseconds in an hour — duration math without inline `1000 * 60 * 60`. */
declare const MS_PER_HOUR = 3600000;
/** Milliseconds in a minute — duration / relative-time math without inline `1000 * 60`. */
declare const MS_PER_MINUTE = 60000;
/** Fixed numeric UK date, e.g. `05/03/2026`. Deliberately NOT org-driven — form-field / compact contexts. */
declare const DISPLAY_DATE_SLASH_FORMAT = "dd/MM/yyyy";
/** Fixed numeric UK datetime, e.g. `05/03/2026 14:30`. Deliberately NOT org-driven. */
declare const DISPLAY_DATETIME_SLASH_FORMAT = "dd/MM/yyyy HH:mm";
/** Weekday + day + abbreviated month, e.g. `Wed 5 Mar`. */
declare const DISPLAY_SHORT_DATE_FORMAT = "EEE d MMM";
/** Type guard: is `value` a bare `yyyy-MM-dd` date-only string? */
declare const isDateOnlyString: (value: unknown) => value is string;
/**
* Formats a `Date`, defaulting to the standard application ISO date format
* (`yyyy-MM-dd`). Pass `dateFormat` to override.
*
* Name note: this `formatDate` takes a `Date`. The org-aware `formatDate` on the
* `@ethisyscore/core-utils/date/org-format` sub-path takes an ISO STRING and
* returns org-configured display text — a different contract that never collides
* because it lives on a different entry point. For the common Date→`yyyy-MM-dd`
* case prefer {@link toIsoDate}, whose name sidesteps the overload.
*/
declare const formatDate: (date: Date, dateFormat?: string) => string;
/** Today's date as a `yyyy-MM-dd` ISO string (local calendar day). */
declare const getTodayIsoDate: () => string;
/**
* Formats a `Date` as a `yyyy-MM-dd` ISO date-only string in local time — the
* inverse of {@link parseIsoDateLocal}. Equivalent to `formatDate(date)`, exposed
* under the clearer name for the date-only round-trip.
*/
declare const toIsoDate: (date: Date) => string;
/**
* Returns a new local `Date` at the first day of `date`'s month, offset by `months`
* (may be negative), normalising the day-of-month to 1 — e.g. offsetting 15 Mar 2026
* by -1 gives 1 Feb 2026, not 15 Feb. Returns an `Invalid Date` for a null/invalid
* input so month-axis arithmetic propagates NaN rather than throwing. Used for
* month-granular axis/range building (e.g. a Gantt chart).
*/
declare const startOfMonthOffset: (date: Date | null | undefined, months: number) => Date;
/**
* Whole-day difference between two `yyyy-MM-dd` date-only strings (`toIso - fromIso`),
* rounded to guard against DST half-day drift when the range crosses a clock-change
* boundary. Parses both bounds as LOCAL dates (via {@link parseIsoDateLocal}); returns
* `NaN` when either is not a valid date-only string.
*/
declare const daysBetweenIso: (fromIso: string, toIso: string) => number;
/** First day of the given date's month, as a `yyyy-MM-dd` ISO string. */
declare const getMonthStartIso: (date: Date) => string;
/** Last day of the given date's month, as a `yyyy-MM-dd` ISO string. */
declare const getMonthEndIso: (date: Date) => string;
/**
* Parses a date-only `yyyy-MM-dd` string as a LOCAL date. Returns `null` when
* the value is not a date-only string or is not a valid calendar date. Avoids
* the `new Date("yyyy-MM-dd")` UTC parse, which shifts the day in non-UTC zones.
*/
declare const parseIsoDateLocal: (value: string | null | undefined) => Date | null;
/**
* Adds `days` to an ISO `yyyy-MM-dd` date and returns the result as a `yyyy-MM-dd`
* string. Parses and formats in local time (via `parseIsoDateLocal` / `formatDate`)
* so the arithmetic can't drift across a day boundary in non-UTC timezones/DST.
* Returns the input unchanged when it is not a valid date-only string.
*/
declare const addDaysToIsoDate: (isoDate: string, days: number) => string;
/**
* Adds `years` to an ISO `yyyy-MM-dd` date and returns the result as a `yyyy-MM-dd`
* string. Parses and formats in local time (like {@link addDaysToIsoDate}) so the
* arithmetic can't drift across a day boundary in non-UTC timezones/DST. Used to seed
* default expiry / end-of-term dates (insurance cover, licences, fixed-term contracts).
* A 29 Feb base in a non-leap target year rolls to 1 Mar, matching `Date.setFullYear`.
* Returns the input unchanged when it is not a valid date-only string.
*/
declare const addYearsToIsoDate: (isoDate: string, years: number) => string;
/**
* Extracts a date-only string (`yyyy-MM-dd`) from a date string.
* - Date-only strings (`2024-05-15`) are returned as-is.
* - ISO datetime strings (`2024-05-15T00:00:00+05:30`) have the date portion
* extracted directly from the string to preserve the original calendar date
* without timezone conversion.
* - Returns empty string for null, undefined, or unparseable values.
*/
declare const toDateOnlyString: (value: string | null | undefined) => string;
/**
* FALLBACK CONVENTION: a display formatter given falsy/unparseable input returns
* the em-dash placeholder {@link EM_DASH} so callers can render unconditionally.
* (Wire/parse helpers in `iso.ts` / `wire.ts` return `""`/`undefined` instead so
* the value is omitted rather than shown; `formatDuration` likewise uses the
* em-dash for missing/invalid input, but `0m` for a real zero.) The one exception
* is {@link formatDateWithOrdinal}, whose "Not specified" / "Invalid date" are
* deliberate, richer domain messages.
*/
declare const EM_DASH = "\u2014";
/**
* Shared relative-time ladder: maps a whole-minute age to a short phrase
* ("Just now", "5m ago", "3h ago", "2d ago"), or `null` for anything a week or
* older so the caller can substitute an absolute date. Backs both
* {@link formatTimeAgo} here and `formatRelativeTime` in the org-format module.
*/
declare const relativeTimePhrase: (diffMinutes: number) => string | null;
/**
* Formats a date-only `yyyy-MM-dd` string in the user's LOCAL timezone as the fixed
* numeric UK date `dd/MM/yyyy`. Parses via {@link parseIsoDateLocal} to avoid the
* `new Date("yyyy-MM-dd")` UTC-midnight parse that renders as the previous day west
* of UTC. Returns the original string when it is not a valid date-only value.
* Deliberately fixed (not org-driven) — for form-field / compact contexts.
*/
declare const formatSlashDate: (dateString: string) => string;
/**
* Formats an ISO datetime string as the fixed numeric UK datetime `dd/MM/yyyy HH:mm`
* for compact display contexts such as table columns. Returns em-dash for missing or
* invalid values. Deliberately fixed (not org-driven) — distinct from the org-aware
* `formatDateTime` in `@ethisyscore/core-utils/date/org-format`.
*/
declare const formatCompactDateTime: (value?: string | null) => string;
/**
* Formats an ISO date/datetime string as a short weekday date `EEE d MMM` (e.g. `Wed 5 Mar`).
* Returns em-dash for missing or invalid values. Deliberately fixed (not org-driven).
*/
declare const formatShortDate: (value?: string | null) => string;
/**
* Formats an ISO date/datetime string as an abbreviated month-day `MMM d` (e.g. `Mar 5`).
* Intended for chart axis ticks where vertical space is limited. Returns em-dash for
* missing or invalid values. Deliberately fixed (not org-driven).
*/
declare const formatMonthDay: (value?: string | null) => string;
/**
* Safely formats a date string or `Date`. Handles null, undefined, and invalid
* dates by returning a fallback string.
* @param date - The date to format (string, Date, null, or undefined)
* @param formatStr - The desired output format (defaults to `DATE_FORMAT`)
* @param fallback - Returned when the date is invalid or missing (defaults to `"—"`)
*/
declare const formatDateSafe: (date: string | Date | null | undefined, formatStr?: string, fallback?: string) => string;
/**
* Formats a date string or `Date` to a format like `31st Aug 2025`.
* Handles date-only strings (`yyyy-MM-dd`) as local dates to avoid timezone shifts.
* @param date - Date string (`yyyy-MM-dd`) or `Date`
* @returns Formatted date string with ordinal suffix
*/
declare const formatDateWithOrdinal: (date: string | Date | null | undefined) => string;
/**
* Formats a date as a relative time string (e.g. `2h ago`, `Just now`).
* Optimised for short labels in dropdowns; anything older than a week falls
* back to the standard date format.
* @param date - ISO string or `Date`
*/
declare const formatTimeAgo: (date: string | Date | null | undefined) => string;
/**
* Structural (token-grammar) validator for date/time format strings — a framework-agnostic
* mirror of the CoreConnect API's `DateFnsFormatValidator` (CoreConnect.Application.Common).
* Accepts any combination of the supported date-fns tokens (a deliberate subset — see the token
* sets below), separators and quoted literals (so users can define custom formats), while unknown
* tokens — incl. .NET-style DD/YYYY/tt, which date-fns either throws on or silently renders as
* garbage — are rejected with a targeted hint.
*
* PARITY CONTRACT: the canonical test vectors in `__tests__/formatValidation.test.ts` are
* duplicated verbatim in the API's `DateFnsFormatValidatorTests.cs`. Error message strings are
* part of the contract — change them in lockstep across both repos.
*/
interface FormatValidationResult {
valid: boolean;
error?: string;
}
/**
* Validates a DATE format string: only supported date-fns date tokens, separators and quoted
* literals; must contain a day, a month and a year token. Nullish or empty input is valid
* (means "unset / use the caller's default"), mirroring the API's `string?` overload — a
* non-empty whitespace-only string is NOT treated as empty and fails the day-token check, matching
* the server's `string.IsNullOrEmpty` semantics.
*/
declare function validateDateFormat(value: string | null | undefined): FormatValidationResult;
/**
* Validates a TIME format string: only supported date-fns time tokens, separators and quoted
* literals; must contain an hour and a minute token; 12-hour tokens require the meridiem token
* 'a' (and vice versa) so an ambiguous 12h-without-AM/PM can never be stored. Nullish or empty
* input is valid (means "unset / use the caller's default"), mirroring the API's `string?`
* overload; a non-empty whitespace-only string is NOT treated as empty and fails the hour-token check.
*/
declare function validateTimeFormat(value: string | null | undefined): FormatValidationResult;
/** Converts a `"HH:mm:ss"` timespan string to milliseconds. */
declare const timespanToMilliseconds: (timespan: string) => number;
/** Converts milliseconds to hours (as a float). */
declare const millisecondsToHours: (ms: number) => number;
/** Converts hours to milliseconds. */
declare const hoursToMilliseconds: (hours: number) => number;
/**
* The one human-readable duration formatter. Takes a MILLISECOND count and renders
* the largest non-zero units as `Xd Xh Xm` (e.g. `4h 15m`, `2d 3h`, `45m`). Zero is
* a real value (`0m`); a nullish/NaN/negative input is missing data and returns the
* em-dash. Minute granularity — seconds are not shown.
*
* Feed non-millisecond inputs through the converters in this module:
* `formatDuration(timespanToMilliseconds("04:15:00"))` // "HH:mm:ss" TimeSpan
* `formatDuration(hoursToMilliseconds(2.5))` // fractional hours
*/
declare const formatDuration: (ms: number | null | undefined) => string;
/**
* Trims an API-supplied `"HH:mm:ss"` down to the `"HH:mm"` string used by
* MUI `TimePicker`-backed forms. Returns the supplied fallback when the value
* is missing or shorter than five characters.
*/
declare function toHHmm(value: string | null | undefined, fallback: string): string;
/**
* Serialises a non-empty `"HH:mm"` / `"HH:mm:ss"` value back to the canonical
* `"HH:mm:ss"` API format. Returns `null` for empty input so callers can block
* the save rather than silently persisting midnight — an empty TimePicker
* (cleared via keyboard) is an unsaved edit, not a legitimate `00:00:00` value.
*/
declare function toHHmmss(value: string): string | null;
/**
* Normalises a date-only value from `` (`yyyy-MM-dd`) into a
* canonical UTC ISO-8601 timestamp at midnight UTC, e.g.
* `2026-07-14` → `2026-07-14T00:00:00.000Z`. Use at the API-payload boundary
* for fields the BE types as `DateTimeOffset` — a bare date-only string risks
* ambiguous/failed deserialisation. A value that is already a full ISO
* timestamp is passed through unchanged. Empty/invalid → `undefined` so callers
* omit the field (BE clears it).
*/
declare function dateOnlyToIsoUtc(value: string | null | undefined): string | undefined;
/**
* Returns the current local wall-clock as a `yyyy-MM-ddTHH:mm` string — the
* format an `` element expects. Minute precision;
* seconds and timezone deliberately omitted.
*/
declare function nowLocalDateTimeInputValue(): string;
/**
* Converts a naive local-time string from ``
* (shape `yyyy-MM-ddTHH:mm` or `yyyy-MM-ddTHH:mm:ss`) into a full ISO-8601 UTC
* string with `Z` suffix that .NET `DateTimeOffset` cannot ambiguously
* interpret. Empty / undefined inputs pass through as `undefined`.
*/
declare function localDateTimeInputToIsoUtc(value: string | null | undefined): string | undefined;
/**
* Ensures an ISO-8601 string is treated as UTC by appending a `Z` suffix when
* no explicit offset or UTC indicator is present. The backend may emit
* timestamps like `2026-05-26T06:21:00` (no Z), which JS would otherwise parse
* as local time.
*/
declare function ensureUtcIso(value: string): string;
/**
* Converts an ISO-8601 string (with or without explicit offset) into the naive
* local-time shape `yyyy-MM-ddTHH:mm` expected by ``.
* Returns the supplied fallback (default empty string) when the input is
* missing or unparseable. When `value` carries no offset or `Z` suffix it is
* treated as UTC before converting to local time, so the edit form displays the
* correct time regardless of the user's timezone.
*/
declare function isoUtcToLocalDateTimeInput(value: string | null | undefined, fallback?: string): string;
interface DateRange {
startDate: string;
endDate: string;
}
/**
* Returns a `{ startDate, endDate }` date range for a named relative period,
* formatted with `dateFormat` (defaults to the ISO date-only format). Unknown
* periods fall back to the last week.
* @param timePeriod - one of `week` | `month` | `quarter` | `year`
* @param dateFormat - output format for both bounds (defaults to `DATE_FORMAT`)
*/
declare const getDateRange: (timePeriod: string, dateFormat?: string) => DateRange;
/** Computes an ISO timestamp range from a number of days back to now. */
declare function computeDateRange(days: number): {
from: string;
to: string;
};
/**
* Returns the current calendar month as a half-open UTC range `[fromUtc, beforeUtc)`,
* suitable for "this month" count filters. `fromUtc` is the first instant of the
* month; `beforeUtc` is the first instant of the next month (exclusive).
*/
declare function currentMonthRangeUtc(today?: Date): {
fromUtc: string;
beforeUtc: string;
};
/**
* Computes the current UTC-offset minutes for a given IANA zone name using the
* runtime's `Intl` implementation. Returns `null` when the zone is unknown.
*
* Used by timezone auto-populate fallbacks so a browser reporting an IANA zone
* that isn't in the backend seed (e.g. `Europe/London` during BST) can still
* match against a seeded zone sharing the same current offset.
*/
declare function getCurrentOffsetMinutes(iana: string): number | null;
export { AUDIT_DATE_FORMAT, DATE_FORMAT, DAY_DATE_FORMAT, DAY_MONTH_FORMAT, DAY_MONTH_YEAR_FORMAT, DISPLAY_DATETIME_SLASH_FORMAT, DISPLAY_DATE_FORMAT, DISPLAY_DATE_SLASH_FORMAT, DISPLAY_SHORT_DATE_FORMAT, type DateRange, EM_DASH, type FormatValidationResult, MS_PER_DAY, MS_PER_HOUR, MS_PER_MINUTE, SHORT_DATETIME_FORMAT, TIME_FORMAT, addDaysToIsoDate, addYearsToIsoDate, computeDateRange, currentMonthRangeUtc, dateOnlyToIsoUtc, daysBetweenIso, ensureUtcIso, formatCompactDateTime, formatDate, formatDateSafe, formatDateWithOrdinal, formatDuration, formatMonthDay, formatShortDate, formatSlashDate, formatTimeAgo, getCurrentOffsetMinutes, getDateRange, getMonthEndIso, getMonthStartIso, getTodayIsoDate, hoursToMilliseconds, isDateOnlyString, isoUtcToLocalDateTimeInput, localDateTimeInputToIsoUtc, millisecondsToHours, nowLocalDateTimeInputValue, parseIsoDateLocal, relativeTimePhrase, startOfMonthOffset, timespanToMilliseconds, toDateOnlyString, toHHmm, toHHmmss, toIsoDate, validateDateFormat, validateTimeFormat };