@trackunit/date-and-time-utils 1.19.1-alpha-f99267f670f.0 → 1.19.2

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.
package/README.md CHANGED
@@ -10,6 +10,12 @@ AI agents should use the machine-readable index at [`/llms.txt`](https://design.
10
10
 
11
11
  For more info and a full guide on Iris App SDK Development, please visit our [Developer Hub](https://developers.trackunit.com/).
12
12
 
13
+ ## System time zone fallback
14
+
15
+ Importing this package patches `Intl.DateTimeFormat.prototype.resolvedOptions` for the whole page. Some browsers report the system `timeZone` as `undefined` when they can't map the OS time zone to an IANA id (for example Chrome on Windows with "British Columbia Standard Time"), which makes the Temporal polyfill throw. The patch fills in the `Etc/GMT` zone for the system's current whole-hour UTC offset (UTC-07:00 becomes `Etc/GMT+7`), or `UTC` otherwise.
16
+
17
+ Browsers that resolve a time zone, explicitly requested time zones and server runtimes are unaffected.
18
+
13
19
  ## Trackunit
14
20
 
15
21
  This package was developed by Trackunit ApS.
package/index.cjs.js CHANGED
@@ -2,6 +2,39 @@
2
2
 
3
3
  var polyfill = require('@js-temporal/polyfill');
4
4
 
5
+ const UTC_TIME_ZONE_ID = "UTC";
6
+ /**
7
+ * Returns the `Etc/GMT` time zone matching the system's current UTC offset, or `UTC` when the
8
+ * offset isn't a whole number of hours. Offset ids like `-07:00` aren't used because the Temporal
9
+ * polyfill can't format dates in them.
10
+ */
11
+ const getSystemOffsetTimeZoneId = () => {
12
+ const offsetHours = -new Date().getTimezoneOffset() / 60;
13
+ // Etc/GMT zones only exist from UTC-12 to UTC+14.
14
+ if (offsetHours === 0 || !Number.isInteger(offsetHours) || offsetHours < -12 || offsetHours > 14) {
15
+ return UTC_TIME_ZONE_ID;
16
+ }
17
+ // Etc/GMT ids use the POSIX sign convention, so UTC-07:00 is Etc/GMT+7.
18
+ return `Etc/GMT${offsetHours > 0 ? "-" : "+"}${Math.abs(offsetHours)}`;
19
+ };
20
+ const SYSTEM_TIME_ZONE_FALLBACK = Symbol.for("@trackunit/date-and-time-utils/system-time-zone-fallback");
21
+ const nativeResolvedOptions = Intl.DateTimeFormat.prototype.resolvedOptions;
22
+ /**
23
+ * Browsers resolve `timeZone` to `undefined` when they can't map the OS time zone to an IANA id
24
+ * (e.g. Chrome with the Windows "British Columbia Standard Time" zone). The Temporal polyfill reads
25
+ * it for `Temporal.Now` and for formatting, and throws on `undefined`, so fill in a fallback zone.
26
+ * Skipped when another copy of this library already installed it.
27
+ */
28
+ if (!(SYSTEM_TIME_ZONE_FALLBACK in nativeResolvedOptions)) {
29
+ Intl.DateTimeFormat.prototype.resolvedOptions = Object.assign(function resolvedOptions() {
30
+ const options = nativeResolvedOptions.call(this);
31
+ if (!options.timeZone) {
32
+ options.timeZone = getSystemOffsetTimeZoneId();
33
+ }
34
+ return options;
35
+ }, { [SYSTEM_TIME_ZONE_FALLBACK]: true });
36
+ }
37
+
5
38
  /**
6
39
  * converts timZoneId to TimeZone object with default to current user timezone
7
40
  *
@@ -128,10 +161,12 @@ const getHourCycle = (locale, hourCycleOverride) => {
128
161
  const formatDateUtil = (date, format, timeZone, locale, hourCycleOverride) => {
129
162
  const hourCycle = getHourCycle(locale, hourCycleOverride);
130
163
  const dateObj = timeZone ? toZonedDateTimeUtil(date, timeZone) : toTemporalUtil(toDateUtil(date));
164
+ // Plain values are formatted in UTC, so the output doesn't depend on the browser's system time zone.
131
165
  if (format?.selectFormat === "dateOnly") {
132
166
  if (dateObj instanceof polyfill.Temporal.ZonedDateTime) {
133
167
  return dateObj.toPlainDate().toLocaleString(locale, {
134
168
  dateStyle: format.dateFormat ?? "medium",
169
+ timeZone: "UTC",
135
170
  });
136
171
  }
137
172
  return dateObj.toLocaleString(locale, {
@@ -144,6 +179,7 @@ const formatDateUtil = (date, format, timeZone, locale, hourCycleOverride) => {
144
179
  return dateObj.toPlainTime().toLocaleString(locale, {
145
180
  timeStyle: format.timeFormat ?? "short",
146
181
  hourCycle,
182
+ timeZone: "UTC",
147
183
  });
148
184
  }
149
185
  return dateObj.toLocaleString(locale, {
package/index.esm.js CHANGED
@@ -1,6 +1,39 @@
1
1
  import { Temporal } from '@js-temporal/polyfill';
2
2
  export { Temporal } from '@js-temporal/polyfill';
3
3
 
4
+ const UTC_TIME_ZONE_ID = "UTC";
5
+ /**
6
+ * Returns the `Etc/GMT` time zone matching the system's current UTC offset, or `UTC` when the
7
+ * offset isn't a whole number of hours. Offset ids like `-07:00` aren't used because the Temporal
8
+ * polyfill can't format dates in them.
9
+ */
10
+ const getSystemOffsetTimeZoneId = () => {
11
+ const offsetHours = -new Date().getTimezoneOffset() / 60;
12
+ // Etc/GMT zones only exist from UTC-12 to UTC+14.
13
+ if (offsetHours === 0 || !Number.isInteger(offsetHours) || offsetHours < -12 || offsetHours > 14) {
14
+ return UTC_TIME_ZONE_ID;
15
+ }
16
+ // Etc/GMT ids use the POSIX sign convention, so UTC-07:00 is Etc/GMT+7.
17
+ return `Etc/GMT${offsetHours > 0 ? "-" : "+"}${Math.abs(offsetHours)}`;
18
+ };
19
+ const SYSTEM_TIME_ZONE_FALLBACK = Symbol.for("@trackunit/date-and-time-utils/system-time-zone-fallback");
20
+ const nativeResolvedOptions = Intl.DateTimeFormat.prototype.resolvedOptions;
21
+ /**
22
+ * Browsers resolve `timeZone` to `undefined` when they can't map the OS time zone to an IANA id
23
+ * (e.g. Chrome with the Windows "British Columbia Standard Time" zone). The Temporal polyfill reads
24
+ * it for `Temporal.Now` and for formatting, and throws on `undefined`, so fill in a fallback zone.
25
+ * Skipped when another copy of this library already installed it.
26
+ */
27
+ if (!(SYSTEM_TIME_ZONE_FALLBACK in nativeResolvedOptions)) {
28
+ Intl.DateTimeFormat.prototype.resolvedOptions = Object.assign(function resolvedOptions() {
29
+ const options = nativeResolvedOptions.call(this);
30
+ if (!options.timeZone) {
31
+ options.timeZone = getSystemOffsetTimeZoneId();
32
+ }
33
+ return options;
34
+ }, { [SYSTEM_TIME_ZONE_FALLBACK]: true });
35
+ }
36
+
4
37
  /**
5
38
  * converts timZoneId to TimeZone object with default to current user timezone
6
39
  *
@@ -127,10 +160,12 @@ const getHourCycle = (locale, hourCycleOverride) => {
127
160
  const formatDateUtil = (date, format, timeZone, locale, hourCycleOverride) => {
128
161
  const hourCycle = getHourCycle(locale, hourCycleOverride);
129
162
  const dateObj = timeZone ? toZonedDateTimeUtil(date, timeZone) : toTemporalUtil(toDateUtil(date));
163
+ // Plain values are formatted in UTC, so the output doesn't depend on the browser's system time zone.
130
164
  if (format?.selectFormat === "dateOnly") {
131
165
  if (dateObj instanceof Temporal.ZonedDateTime) {
132
166
  return dateObj.toPlainDate().toLocaleString(locale, {
133
167
  dateStyle: format.dateFormat ?? "medium",
168
+ timeZone: "UTC",
134
169
  });
135
170
  }
136
171
  return dateObj.toLocaleString(locale, {
@@ -143,6 +178,7 @@ const formatDateUtil = (date, format, timeZone, locale, hourCycleOverride) => {
143
178
  return dateObj.toPlainTime().toLocaleString(locale, {
144
179
  timeStyle: format.timeFormat ?? "short",
145
180
  hourCycle,
181
+ timeZone: "UTC",
146
182
  });
147
183
  }
148
184
  return dateObj.toLocaleString(locale, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/date-and-time-utils",
3
- "version": "1.19.1-alpha-f99267f670f.0",
3
+ "version": "1.19.2",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -0,0 +1,9 @@
1
+ declare const UTC_TIME_ZONE_ID = "UTC";
2
+ /**
3
+ * Returns the `Etc/GMT` time zone matching the system's current UTC offset, or `UTC` when the
4
+ * offset isn't a whole number of hours. Offset ids like `-07:00` aren't used because the Temporal
5
+ * polyfill can't format dates in them.
6
+ */
7
+ declare const getSystemOffsetTimeZoneId: () => string;
8
+ declare const SYSTEM_TIME_ZONE_FALLBACK: unique symbol;
9
+ declare const nativeResolvedOptions: () => Intl.ResolvedDateTimeFormatOptions;
package/src/temporal.d.ts CHANGED
@@ -1 +1,2 @@
1
+ import "./systemTimeZone";
1
2
  export { Temporal } from "@js-temporal/polyfill";
@@ -1 +0,0 @@
1
- {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../../../../libs/date-and-time/utils/migrations/entry.ts"],"names":[],"mappings":"","sourcesContent":["export {};\n"]}