import { DateTimePatternFieldType } from '@phensley/cldr-types'; import { DateFormatOptions, DateIntervalFormatOptions } from '../../common'; import { NumberParams } from '../../common/private'; import { Bundle } from '../../resource'; import { CalendarDate } from '../../systems/calendars'; import { Internals } from '../internals'; import { CalendarPatterns } from './patterns'; import { DateSkeleton } from './skeleton'; import { DateFormatRequest, DateIntervalFormatRequest } from './types'; export declare class CalendarManager { private readonly bundle; private readonly internals; private readonly patternCache; private readonly availableCalendars; constructor(bundle: Bundle, internals: Internals); getCalendarPatterns(calendar: string): CalendarPatterns; getDateFormatRequest(date: CalendarDate, options: DateFormatOptions, params: NumberParams): DateFormatRequest; /** * Formats datetime intervals. * * NOTE: The ICU implementation of CLDR datetime range formatting * contains inconsistent behavior (see code at end of comment below). * * The skeleton data for interval formatting consists of a series of * separate date and time patterns. No interval skeletons / formats * contain both date and time fields. * * For example, the data might contain the following: * * ['y', 'yM', 'yMd', 'h', 'hm', 'H', 'Hm'] * * However a caller can pass input skeleton containing a mix of date and * time fields. We split this skeleton into separate date and time * skeletons, and perform formatting by considering the possibilities below. * * Variables: * * start = start datetime * end = end datetime * skeleton = input skeleton * fovd = fieldOfVisualDifference(start, end) * date_differs = fovd in ('era', 'year', 'month', 'day') * time_differs = fovd in ('dayperiod', 'hour', 'minute') * equal = fovd in ('second', undefined) * * Formatting Rules: * * 1. Skeleton requests both date and time fields * * a. IF time_differs, format date followed by time range * e.g. "date, time0 - time 1" * * b. ELSE IF date_differs, format generic fallback * e.g. "date0, time0 - date1, time1" * * c. ELSE format the date + time standalone * e.g. "date0, time0" * * 2: Skeleton only requests date fields * * a. IF date_differs, format date range * e.g. "date0 - date1" * * b. ELSE format date standalone * * 3: Skeleton only requests time fields * * a. IF time_differs, format time range * e.g. "time0 - time1" * * b. ELSE format time standalone * * ======================================================== * * Example of inconsistency of ICU range formatting. * The output was produced using Node 23.7.0 and ICU 74. * ICU4J version 75 produces the same output. * * const OPTS = [ * { day: 'numeric' }, * { day: 'numeric', minute: '2-digit' } * ]; * const start = new Date(Date.UTC(2007, 0, 1, 10, 12, 0)); * const end = new Date(Date.UTC(2008, 0, 2, 11, 13, 0)); * for (let i = 0; i < OPTS.length; i++) { * const opts = OPTS[i]; * const fmt = new Intl.DateTimeFormat('en', opts); * console.log(fmt.formatRange(start, end)); * } * * This code formats two dates two different ways: * * 2007-Jan-01 10:12 * 2008-Jan-02 11:13 * * 1. Display the day: { day: 'numeric' } * * ICU auto-expands the selected pattern to include the year * and month: * * "1/1/2007 – 1/2/2008" * * This adds context needed to understand the two * dates are separated by 367 days. * * 2. Display day and minute: { day: 'numeric', minute: '2-digit' } * * No pattern expansion occurs, we get only what we * requested. The output is highly ambiguous since it's * missing year, month, and hour fields: * * "1, 12 – 2, 13" * * Additional context is added in one case but not in the other. * * IMO it makes more sense to leave the input skeleton as untouched * as possible, leaving it up to the caller to decide which * fields to request. */ getDateIntervalFormatRequest(calendar: string, start: CalendarDate, end: CalendarDate, options: DateIntervalFormatOptions, params: NumberParams): DateIntervalFormatRequest; largestSkeletonField(skeleton: DateSkeleton): DateTimePatternFieldType; maskedFOVD(start: CalendarDate, end: CalendarDate, skeleton: DateSkeleton): DateTimePatternFieldType; private dayperiodFlex; private matchAvailablePattern; private getAvailablePattern; /** * Select appropriate wrapper based on fields in the date skeleton. */ private selectWrapper; private supportedOption; }