@formatjs/intl-datetimeformat 7.1.0 → 7.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -105,7 +105,18 @@ export function FormatDateTimePattern(dtf, patternParts, x, _a) {
105
105
  var timeZone = internalSlots.timeZone || getDefaultTimeZone();
106
106
  var timeZoneData = timeZoneName[timeZone];
107
107
  if (timeZoneData && timeZoneData[f]) {
108
- fv = timeZoneData[f][+tm.inDST];
108
+ var names = timeZoneData[f];
109
+ // GH #5114: If in DST and both standard/daylight names are the same,
110
+ // fall back to GMT offset format (matches native browser behavior).
111
+ // This handles locales where CLDR doesn't provide a daylight name.
112
+ // NOTE: This is a formatjs implementation detail - ECMA-402 doesn't
113
+ // explicitly specify behavior for missing DST names in locale data.
114
+ if (tm.inDST && names.length >= 2 && names[0] === names[1]) {
115
+ fv = offsetToGmtString(gmtFormat, hourFormat, tm.timeZoneOffset, f);
116
+ }
117
+ else {
118
+ fv = names[+tm.inDST];
119
+ }
109
120
  }
110
121
  else {
111
122
  // Fallback to gmtFormat
@@ -1,11 +1,84 @@
1
1
  import { DateFromTime, HourFromTime, MinFromTime, MonthFromTime, SecFromTime, WeekDay, YearFromTime, invariant, msFromTime, } from '@formatjs/ecma402-abstract';
2
+ // Cached regex patterns for performance
3
+ var OFFSET_TIMEZONE_PREFIX_REGEX = /^[+-]/;
4
+ var OFFSET_TIMEZONE_FORMAT_REGEX = /^([+-])(\d{2})(?::?(\d{2}))?(?::?(\d{2}))?(?:\.(\d{1,9}))?$/;
5
+ /**
6
+ * IsTimeZoneOffsetString ( offsetString )
7
+ * https://tc39.es/ecma262/#sec-istimezoneoffsetstring
8
+ *
9
+ * Determines if a string is a UTC offset identifier.
10
+ *
11
+ * @param offsetString - The string to check
12
+ * @returns true if offsetString is a UTC offset format
13
+ */
14
+ function IsTimeZoneOffsetString(offsetString) {
15
+ return OFFSET_TIMEZONE_PREFIX_REGEX.test(offsetString);
16
+ }
17
+ /**
18
+ * ParseTimeZoneOffsetString ( offsetString )
19
+ * https://tc39.es/ecma262/#sec-parsetimezoneoffsetstring
20
+ *
21
+ * Parses a UTC offset string and returns the offset in milliseconds.
22
+ * This is used to calculate the timezone offset for ToLocalTime.
23
+ *
24
+ * Supports formats: ±HH, ±HHMM, ±HH:MM, ±HH:MM:SS, ±HH:MM:SS.sss
25
+ *
26
+ * @param offsetString - The UTC offset string to parse (e.g., "+01:00")
27
+ * @returns The offset in milliseconds
28
+ */
29
+ function ParseTimeZoneOffsetString(offsetString) {
30
+ // 1. Let parseResult be ParseText(offsetString, UTCOffset)
31
+ var match = OFFSET_TIMEZONE_FORMAT_REGEX.exec(offsetString);
32
+ // 2. Assert: parseResult is not a List of errors
33
+ if (!match) {
34
+ return 0;
35
+ }
36
+ // 3. Extract components from parseResult
37
+ var sign = match[1] === '+' ? 1 : -1;
38
+ var hours = parseInt(match[2], 10);
39
+ var minutes = match[3] ? parseInt(match[3], 10) : 0;
40
+ var seconds = match[4] ? parseInt(match[4], 10) : 0;
41
+ var fractionalStr = match[5] || '0';
42
+ // 4. Convert fractional seconds (nanoseconds) to milliseconds
43
+ // Pad to 9 digits and divide by 1000000
44
+ // Use manual padding for compatibility (padEnd is ES2017)
45
+ var paddedFractional = (fractionalStr + '000000000').slice(0, 9);
46
+ var fractional = parseInt(paddedFractional, 10) / 1000000;
47
+ // 5. Calculate total offset in milliseconds
48
+ // offset = sign × (hours × 3600000 + minutes × 60000 + seconds × 1000 + fractional)
49
+ var offsetMs = sign * (hours * 3600000 + minutes * 60000 + seconds * 1000 + fractional);
50
+ // 6. Return offset in milliseconds
51
+ return offsetMs;
52
+ }
53
+ /**
54
+ * GetNamedTimeZoneOffsetNanoseconds ( timeZone, t )
55
+ * Similar to abstract operation in ECMA-262, adapted for IANA timezone data.
56
+ * Extended to support UTC offset time zones per ECMA-402 PR #788.
57
+ *
58
+ * Returns the timezone offset in milliseconds (not nanoseconds for this impl)
59
+ * and DST flag for the given timezone at time t.
60
+ *
61
+ * @param t - Time value in milliseconds since epoch
62
+ * @param timeZone - The timezone identifier
63
+ * @param tzData - IANA timezone database
64
+ * @returns Tuple of [offset in milliseconds, inDST boolean]
65
+ */
2
66
  function getApplicableZoneData(t, timeZone, tzData) {
3
67
  var _a;
68
+ // 1. If IsTimeZoneOffsetString(timeZone) is true, then
69
+ // a. Let offsetNs be ParseTimeZoneOffsetString(timeZone)
70
+ // b. Return offsetNs (no DST for offset timezones)
71
+ if (IsTimeZoneOffsetString(timeZone)) {
72
+ var offsetMs = ParseTimeZoneOffsetString(timeZone);
73
+ return [offsetMs, false]; // UTC offset timezones never observe DST
74
+ }
75
+ // 2. Let timeZoneData be the IANA Time Zone Database entry for timeZone
4
76
  var zoneData = tzData[timeZone];
5
- // We don't have data for this so just say it's UTC
77
+ // 3. If no data available, treat as UTC (0 offset, no DST)
6
78
  if (!zoneData) {
7
79
  return [0, false];
8
80
  }
81
+ // 4. Find the applicable transition for time t
9
82
  var i = 0;
10
83
  var offset = 0;
11
84
  var dst = false;
@@ -16,6 +89,7 @@ function getApplicableZoneData(t, timeZone, tzData) {
16
89
  break;
17
90
  }
18
91
  }
92
+ // 5. Return offset in milliseconds and DST flag
19
93
  return [offset * 1e3, dst];
20
94
  }
21
95
  /**
package/src/core.js CHANGED
@@ -8,7 +8,7 @@ import { FormatDateTimeToParts } from './abstract/FormatDateTimeToParts.js';
8
8
  import { InitializeDateTimeFormat } from './abstract/InitializeDateTimeFormat.js';
9
9
  import { parseDateTimeSkeleton } from './abstract/skeleton.js';
10
10
  import { DATE_TIME_PROPS } from './abstract/utils.js';
11
- import links from './data/links.js';
11
+ import links from './data/links.generated.js';
12
12
  import getInternalSlots from './get_internal_slots.js';
13
13
  import { unpack } from './packer.js';
14
14
  var UPPERCASED_LINKS = Object.keys(links).reduce(function (all, l) {