1const DEFAULT_DATE_FORMAT = 'mm-dd-yyyy'; 2const DATE_FORMAT_BY_LANGUAGE = Object.freeze({ 3 de: 'dd-mm-yyyy', 4 en: DEFAULT_DATE_FORMAT, 5 es: 'dd-mm-yyyy', 6 fr: 'dd-mm-yyyy', 7 nl: 'dd-mm-yyyy', 8 pl: 'dd-mm-yyyy', 9 sl: 'dd-mm-yyyy', 10 sv: 'dd-mm-yyyy', 11}); 12const intlFormatterCache = new Map(); 13const localeDateFormatCache = new Map(); 14 15// API dates are independent of the host's display format and browser timezone. 16// Never guess whether localized text such as 01-12-2028 is day- or month-first. 17const parseApiDate = (value) => { 18 if (value instanceof Date) { 19 return Number.isFinite(value.getTime()) ? new Date(value.getTime()) : null; 20 } 21 if (typeof value !== 'string') return null; 22 23 const text = value.trim(); 24 const match = text.match( 25 /^(\d{4}-\d{2}-\d{2})(?:[T ]([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d)(\.\d+)?)?(Z|[+-](?:[01]\d|2[0-3]):?[0-5]\d)?)?$/i, 26 ); 27 if (!match) return null; 28 29 const calendarDay = new Date(`${match[1]}T00:00:00Z`); 30 if (!Number.isFinite(calendarDay.getTime()) || calendarDay.toISOString().slice(0, 10) !== match[1]) { 31 return null; 32 } 33 const offset = (match[6] || 'Z').toUpperCase().replace(/^([+-]\d{2})(\d{2})$/, '$1:$2'); 34 const fraction = match[5] ? match[5].padEnd(4, '0').slice(0, 4) : ''; 35 const timestamp = match[2] 36 ? `${match[1]}T${match[2]}:${match[3]}:${match[4] || '00'}${fraction}${offset}` 37 : `${match[1]}T00:00:00Z`; 38 const date = new Date(timestamp); 39 return Number.isFinite(date.getTime()) ? date : null; 40}; 41 42const padDatePart = (value, length = 2) => String(value).padStart(length, '0'); 43 44const getIntlFormatter = (locale, options) => { 45 const normalizedLocale = locale || 'en'; 46 const cacheKey = JSON.stringify([normalizedLocale, options]); 47 if (intlFormatterCache.has(cacheKey)) { 48 return intlFormatterCache.get(cacheKey); 49 } 50 51 try { 52 const formatter = new Intl.DateTimeFormat(normalizedLocale, options); 53 intlFormatterCache.set(cacheKey, formatter); 54 return formatter; 55 } catch { 56 if (normalizedLocale !== 'en') { 57 return getIntlFormatter('en', options); 58 } 59 return null; 60 } 61}; 62 63const formatWithIntl = (date, locale, options) => { 64 const formatter = getIntlFormatter(locale, options); 65 return formatter ? formatter.format(date) : ''; 66}; 67 68const getLocaleDateFormat = (locale) => { 69 const normalizedLocale = locale || 'en'; 70 if (localeDateFormatCache.has(normalizedLocale)) { 71 return localeDateFormatCache.get(normalizedLocale); 72 } 73 74 const language = String(normalizedLocale).trim().toLowerCase().split(/[-_]/)[0]; 75 let format = DATE_FORMAT_BY_LANGUAGE[language]; 76 if (!format) { 77 format = DEFAULT_DATE_FORMAT; 78 try { 79 const parts = new Intl.DateTimeFormat(normalizedLocale, { 80 day: '2-digit', 81 month: '2-digit', 82 year: 'numeric', 83 }).formatToParts(new Date(2000, 10, 22)); 84 const dayIndex = parts.findIndex((part) => part.type === 'day'); 85 const monthIndex = parts.findIndex((part) => part.type === 'month'); 86 format = dayIndex >= 0 && monthIndex >= 0 && dayIndex < monthIndex ? 'dd-mm-yyyy' : DEFAULT_DATE_FORMAT; 87 } catch {} 88 } 89 90 localeDateFormatCache.set(normalizedLocale, format); 91 return format; 92}; 93 94const getPublicAppLocale = () => { 95 if (typeof globalThis === 'undefined' || !globalThis) { 96 return ''; 97 } 98 99 const publicEnv = globalThis.PUBLIC_ENV || globalThis.window?.PUBLIC_ENV; 100 const locale = publicEnv?.PUBLIC_APP_LANGUAGE; 101 return locale === null || locale === undefined ? '' : String(locale).trim(); 102}; 103 104const getDefaultDateFormat = (locale) => getLocaleDateFormat(getPublicAppLocale() || locale || 'en'); 105 106const formatLocaleTime = (date, locale, timeZone) => { 107 try { 108 return date.toLocaleTimeString(locale || undefined, timeZone ? { timeZone } : undefined); 109 } catch { 110 return date.toLocaleTimeString(); 111 } 112}; 113 114const formatDate = ( 115 inputDate, 116 { withTime = true, format, twoDigitYear = false, locale = 'en', fallback = '', timeZone, intlOptions } = {}, 117) => { 118 if (inputDate === null || inputDate === undefined || inputDate === '') return fallback; 119 120 const date = inputDate instanceof Date ? new Date(inputDate.getTime()) : new Date(inputDate); 121 if (Number.isNaN(date.getTime())) return fallback; 122 123 if (intlOptions && typeof intlOptions === 'object') { 124 const label = formatWithIntl(date, locale, timeZone ? { ...intlOptions, timeZone } : intlOptions); 125 return label || fallback; 126 } 127 128 const useUtc = String(timeZone || '').toUpperCase() === 'UTC';
129 const fullYear = useUtc ? date.getUTCFullYear() : date.getFullYear(); 130 const year = twoDigitYear ? padDatePart(fullYear % 100) : padDatePart(fullYear, 4); 131 const month = padDatePart((useUtc ? date.getUTCMonth() : date.getMonth()) + 1); 132 const day = padDatePart(useUtc ? date.getUTCDate() : date.getDate()); 133 const resolvedFormat = String(format || getDefaultDateFormat(locale)); 134 const dayFirst = resolvedFormat.trim().toLowerCase().startsWith('d'); 135 const dateLabel = dayFirst ? `${day}-${month}-${year}` : `${month}-${day}-${year}`; 136 137 if (!withTime) return dateLabel; 138 139 const timeLabel = dayFirst 140 ? `${padDatePart(useUtc ? date.getUTCHours() : date.getHours())}:${padDatePart( 141 useUtc ? date.getUTCMinutes() : date.getMinutes(), 142 )}` 143 : formatLocaleTime(date, locale, timeZone); 144 return `${dateLabel} ${timeLabel}`; 145}; 146 147const DATE_CORE = { 148 DEFAULT_DATE_FORMAT, 149 formatDate, 150 getDefaultDateFormat, 151 parseApiDate, 152}; 153 154if (typeof globalThis !== 'undefined' && globalThis) { 155 globalThis.DATE_CORE = DATE_CORE; 156} 157 158if (typeof module !== 'undefined' && module.exports) { 159 module.exports = DATE_CORE; 160}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.