/** * 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 };