nhb-toolbox 4.26.45 → 4.26.50

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/CHANGELOG.md CHANGED
@@ -6,6 +6,11 @@ All notable changes to the package will be documented here.
6
6
 
7
7
  ---
8
8
 
9
+ ## [4.26.50] - 2025-11-14
10
+
11
+ - **Updated** `TimeZoneIdentifier` type: now **excludes** `Factory` and *time zone abbreviations* already present in `TimeZone` literal type. **Created** new `$TimeZoneIdentifier` type as *replacement*.
12
+ - **Replaced** `TIME_ZONE_IDS` with `Intl.supportedValuesOf('timeZone')` API to get *time zone identifier* to reduce the `timeZonePlugin` size. `TIME_ZONE_IDS` is still in the codebase to generate *types*.
13
+
9
14
  ## [4.26.45] - 2025-11-13
10
15
 
11
16
  - **Removed** *time zone id* `'Factory'` from `TIME_ZONE_IDS` and **replaced** `'EDT'` with `'EST5EDT'` to fix the *issue with getting time zone details* using `Intl` API.
@@ -159,12 +159,17 @@ class Chronos {
159
159
  return instance;
160
160
  }
161
161
  #getNativeTzName(tzId) {
162
- const tzDetails = new Intl.DateTimeFormat('en', {
163
- timeZone: tzId,
164
- timeZoneName: 'long',
165
- }).formatToParts(this.#date);
166
- const tzPart = tzDetails.find((p) => p.type === 'timeZoneName');
167
- return tzPart?.value;
162
+ try {
163
+ const tzDetails = new Intl.DateTimeFormat('en', {
164
+ timeZone: tzId,
165
+ timeZoneName: 'long',
166
+ }).formatToParts(this.#date);
167
+ const tzPart = tzDetails.find((p) => p.type === 'timeZoneName');
168
+ return tzPart?.value;
169
+ }
170
+ catch {
171
+ return undefined;
172
+ }
168
173
  }
169
174
  #format(format, useUTC = false) {
170
175
  const year = useUTC ? this.#date.getUTCFullYear() : this.#date.getFullYear();
@@ -23,7 +23,7 @@ function isValidUTCOffset(value) {
23
23
  return (0, primitives_1.isString)(value) ? /^UTC[+-]?\d{1,2}:\d{2}$/.test(value) : false;
24
24
  }
25
25
  function isValidTimeZoneId(value) {
26
- return (0, primitives_1.isString)(value) ? value in timezone_1.TIME_ZONE_IDS : false;
26
+ return (0, primitives_1.isString)(value) ? value !== 'Factory' && value in timezone_1.TIME_ZONE_IDS : false;
27
27
  }
28
28
  function isLeapYear(year) {
29
29
  const $year = (0, utilities_1.normalizeNumber)(year);
@@ -7,15 +7,15 @@ const timezone_1 = require("../timezone");
7
7
  const utils_1 = require("../utils");
8
8
  const timeZonePlugin = (ChronosClass) => {
9
9
  const { internalDate: $Date, withOrigin } = ChronosClass[constants_1.INTERNALS];
10
+ const TZ_IDS = Intl.supportedValuesOf('timeZone');
10
11
  const _isGMT = (factor) => {
11
12
  return factor === 'UTC+00:00' || factor === 'UTC-00:00';
12
13
  };
13
- const TZ_NAME_ABBR_MAP = new Map(Object.entries(timezone_1.TIME_ZONES).map(([tzAbbr, { offset, tzName }]) => [
14
- offset,
15
- { tzAbbr, tzName },
16
- ]));
17
14
  const _isLabelKey = (offset) => {
18
- return offset in timezone_1.TIME_ZONE_LABELS;
15
+ return offset ? offset in timezone_1.TIME_ZONE_LABELS : false;
16
+ };
17
+ const _isValidTzAbbr = (tz) => {
18
+ return tz in timezone_1.TIME_ZONES;
19
19
  };
20
20
  const _resolveTzName = (offset) => {
21
21
  if (_isLabelKey(offset)) {
@@ -23,6 +23,51 @@ const timeZonePlugin = (ChronosClass) => {
23
23
  }
24
24
  return undefined;
25
25
  };
26
+ const _getTimeZoneDetails = (tzId, date) => {
27
+ const TZ_NAME_TYPES = ['long', 'longOffset'];
28
+ const obj = { tzId };
29
+ for (const type of TZ_NAME_TYPES) {
30
+ const key = type === 'long' ? 'tzName' : 'offset';
31
+ try {
32
+ const parts = new Intl.DateTimeFormat('en', {
33
+ timeZone: tzId,
34
+ timeZoneName: type,
35
+ }).formatToParts(date);
36
+ const tzPart = parts.find((p) => p.type === 'timeZoneName');
37
+ const value = type === 'longOffset' ?
38
+ tzPart?.value === 'GMT' ?
39
+ 'UTC+00:00'
40
+ : tzPart?.value?.replace(/^GMT/, 'UTC')
41
+ : tzPart?.value;
42
+ obj[key] = value;
43
+ }
44
+ catch {
45
+ obj[key] = undefined;
46
+ }
47
+ }
48
+ return obj;
49
+ };
50
+ const TZ_ID_MAP = new Map(TZ_IDS.reduce((tzIds, id) => {
51
+ const { offset } = _getTimeZoneDetails(id);
52
+ if (offset) {
53
+ const arr = tzIds.get(offset) ?? [];
54
+ arr.push(id);
55
+ tzIds.set(offset, arr);
56
+ }
57
+ return tzIds;
58
+ }, new Map()));
59
+ const TZ_NAME_ABBR_MAP = new Map(Object.entries(timezone_1.TIME_ZONES).map(([tzAbbr, { offset, tzName }]) => [
60
+ offset,
61
+ { tzAbbr, tzName },
62
+ ]));
63
+ const _getTimeZoneId = (utc) => {
64
+ const tzIds = TZ_ID_MAP.get(utc);
65
+ if (!tzIds || tzIds?.length === 0)
66
+ return undefined;
67
+ if (tzIds?.length === 1)
68
+ return tzIds[0];
69
+ return tzIds;
70
+ };
26
71
  const _getTimeZoneName = (zone, date) => {
27
72
  if (_isGMT(zone))
28
73
  return 'Greenwich Mean Time';
@@ -33,34 +78,14 @@ const timeZonePlugin = (ChronosClass) => {
33
78
  }
34
79
  return tzName;
35
80
  }
36
- else if ((0, guards_1.isValidTimeZoneId)(zone)) {
37
- const { offset, tzName } = timezone_1.TIME_ZONE_IDS[zone];
38
- const { tzNameLongOffset, tzNameLong } = (0, utils_1.getTimeZoneDetails)(zone, date);
39
- const convertedOffset = tzNameLongOffset?.replace(/^GMT/, 'UTC') ?? '';
40
- const resolvedName = _resolveTzName(offset);
41
- const priorityName = convertedOffset === offset ? tzNameLong : resolvedName;
42
- return tzName || priorityName || resolvedName || tzNameLong;
81
+ else if (_isValidTzAbbr(zone)) {
82
+ return timezone_1.TIME_ZONES[zone].tzName;
43
83
  }
44
84
  else {
45
- return zone in timezone_1.TIME_ZONES ?
46
- timezone_1.TIME_ZONES[zone].tzName
47
- : _resolveTzName(timezone_1.TIME_ZONES[zone]?.offset);
85
+ const { offset, tzName } = _getTimeZoneDetails(zone, date);
86
+ return tzName || _resolveTzName(offset);
48
87
  }
49
88
  };
50
- const TZ_ID_MAP = new Map(Object.entries(timezone_1.TIME_ZONE_IDS).reduce((acc, [id, { offset }]) => {
51
- const arr = acc.get(offset) ?? [];
52
- arr.push(id);
53
- acc.set(offset, arr);
54
- return acc;
55
- }, new Map()));
56
- const _getTimeZoneId = (utc) => {
57
- const tzIds = TZ_ID_MAP.get(utc);
58
- if (!tzIds || tzIds?.length === 0)
59
- return undefined;
60
- if (tzIds?.length === 1)
61
- return tzIds[0];
62
- return tzIds;
63
- };
64
89
  ChronosClass.prototype.timeZone = function (zone) {
65
90
  let offset;
66
91
  let tzId;
@@ -68,13 +93,13 @@ const timeZonePlugin = (ChronosClass) => {
68
93
  offset = zone;
69
94
  tzId = _getTimeZoneId(offset) || offset;
70
95
  }
71
- else if ((0, guards_1.isValidTimeZoneId)(zone)) {
72
- offset = timezone_1.TIME_ZONE_IDS[zone].offset;
73
- tzId = zone;
96
+ else if (_isValidTzAbbr(zone)) {
97
+ offset = timezone_1.TIME_ZONES[zone].offset;
98
+ tzId = _getTimeZoneId(offset) || offset;
74
99
  }
75
100
  else {
76
- offset = zone in timezone_1.TIME_ZONES ? timezone_1.TIME_ZONES[zone].offset : timezone_1.TIME_ZONES['UTC'].offset;
77
- tzId = _getTimeZoneId(offset) || offset;
101
+ offset = _getTimeZoneDetails(zone, $Date(this)).offset || timezone_1.TIME_ZONES['UTC'].offset;
102
+ tzId = zone;
78
103
  }
79
104
  const $zone = zone || offset;
80
105
  const tzName = _getTimeZoneName($zone, $Date(this)) ?? offset;
@@ -121,7 +146,7 @@ const timeZonePlugin = (ChronosClass) => {
121
146
  const zone = _getTimeZoneName(tzMapKey, $Date(this)) ?? UTC;
122
147
  if (TZ_ABBR_CACHE.has(`name-${zone}`))
123
148
  return TZ_ABBR_CACHE.get(zone);
124
- const customAbbr = (0, guards_1.isValidUTCOffset)(zone) || (0, guards_1.isValidTimeZoneId)(zone) ? zone : _abbreviate(zone);
149
+ const customAbbr = (0, guards_1.isValidUTCOffset)(zone) ? zone : _abbreviate(zone);
125
150
  TZ_ABBR_CACHE.set(`name-${zone}`, customAbbr);
126
151
  return customAbbr;
127
152
  };
@@ -2861,6 +2861,10 @@ exports.TIME_ZONE_IDS = /* @__PURE__ */ Object.freeze({
2861
2861
  tzName: 'Central European Time',
2862
2862
  offset: 'UTC+01:00',
2863
2863
  },
2864
+ Factory: {
2865
+ tzName: undefined,
2866
+ offset: 'UTC+00:00',
2867
+ },
2864
2868
  GB: {
2865
2869
  tzName: 'Greenwich Mean Time',
2866
2870
  offset: 'UTC+00:00',
@@ -44,13 +44,18 @@ function getTimeZoneDetails(tzId, date) {
44
44
  const $tzId = tzId || Intl.DateTimeFormat().resolvedOptions().timeZone;
45
45
  const obj = { tzIdentifier: $tzId };
46
46
  for (const type of TZ_NAME_TYPES) {
47
- const parts = new Intl.DateTimeFormat('en', {
48
- timeZone: $tzId,
49
- timeZoneName: type,
50
- }).formatToParts(date);
51
- const tzPart = parts.find((p) => p.type === 'timeZoneName');
52
47
  const key = `tzName${type[0].toUpperCase()}${type.slice(1)}`;
53
- obj[key] = tzPart?.value;
48
+ try {
49
+ const parts = new Intl.DateTimeFormat('en', {
50
+ timeZone: $tzId,
51
+ timeZoneName: type,
52
+ }).formatToParts(date);
53
+ const tzPart = parts.find((p) => p.type === 'timeZoneName');
54
+ obj[key] = tzPart?.value;
55
+ }
56
+ catch {
57
+ obj[key] = undefined;
58
+ }
54
59
  }
55
60
  return obj;
56
61
  }
@@ -1,7 +1,7 @@
1
1
  import type { Enumerate, NumberRange } from '../number/types';
2
2
  import type { LooseLiteral, TupleOf } from '../utils/types';
3
3
  import { INTERNALS } from './constants';
4
- import type { $UTCOffset, ChronosInput, ChronosInternals, ChronosMethods, ChronosObject, ChronosPlugin, ChronosWithOptions, DateRangeOptions, DateTimeFormatOptions, FormatOptions, LocalesArguments, Milliseconds, MonthName, Quarter, RangeWithDates, RelativeDateRange, RelativeRangeOptions, StrictFormat, TimeParts, TimeUnit, TimeUnitValue, TimeZone, TimeZoneId, TimeZoneIdentifier, TimeZoneName, UTCOffset, WeekDay } from './types';
4
+ import type { $TimeZoneIdentifier, $UTCOffset, ChronosInput, ChronosInternals, ChronosMethods, ChronosObject, ChronosPlugin, ChronosWithOptions, DateRangeOptions, DateTimeFormatOptions, FormatOptions, LocalesArguments, Milliseconds, MonthName, Quarter, RangeWithDates, RelativeDateRange, RelativeRangeOptions, StrictFormat, TimeParts, TimeUnit, TimeUnitValue, TimeZone, TimeZoneId, TimeZoneName, UTCOffset, WeekDay } from './types';
5
5
  /**
6
6
  * * Creates a new immutable `Chronos` instance.
7
7
  *
@@ -55,18 +55,18 @@ export declare class Chronos {
55
55
  /**
56
56
  * Represents the current timezone context, which can be a single identifier, an array of equivalent identifiers, or a UTC offset.
57
57
  *
58
- * - **`TimeZoneIdentifier`** — e.g., `"Asia/Dhaka"`. Returned when the {@link timeZone} method has not been invoked. It is default behaviour.
59
- * - **Array of `TimeZoneIdentifier`** — e.g., `['Asia/Kathmandu', 'Asia/Katmandu']`, used when multiple timezones share the same UTC offset such as `"UTC+05:45"`.
60
- * - **`UTCOffset`** — e.g., `"UTC+06:45"` or `"UTC+02:15"`, returned when no named timezone corresponds to a given offset.
58
+ * - **{@link $TimeZoneIdentifier}** — e.g., `"Asia/Dhaka"`. Returned when the {@link timeZone} method has not been invoked. It is default behaviour.
59
+ * - **Array of {@link $TimeZoneIdentifier}** — e.g., `['Asia/Kathmandu', 'Asia/Katmandu']`, used when multiple timezones share the same UTC offset such as `"UTC+05:45"`.
60
+ * - **{@link UTCOffset}** — e.g., `"UTC+06:45"` or `"UTC+02:15"`, returned when no named timezone corresponds to a given offset.
61
61
  *
62
62
  * @remarks
63
- * - By default, when {@link timeZone} is not applied, a single `TimeZoneIdentifier` string is provided.
63
+ * - By default, when {@link timeZone} is not applied, a single {@link $TimeZoneIdentifier} string is provided.
64
64
  * - When applied, it may instead return a single identifier string, an array of equivalent identifiers or a UTC offset string.
65
65
  * - To retrieve the local system's native timezone identifier, use the {@link $getNativeTimeZoneId} instance method.
66
66
  */
67
67
  timeZoneId: TimeZoneId;
68
68
  /** Tracker to identify the instance created by {@link timeZone} method */
69
- protected $tzTracker?: TimeZoneIdentifier | TimeZone | UTCOffset;
69
+ protected $tzTracker?: $TimeZoneIdentifier | TimeZone | UTCOffset;
70
70
  /**
71
71
  * * Creates a new immutable `Chronos` instance.
72
72
  *
@@ -161,7 +161,7 @@ export declare class Chronos {
161
161
  *
162
162
  * @returns The resolved time zone name or its IANA identifier as a fallback.
163
163
  */
164
- $getNativeTimeZoneName(tzId?: TimeZoneIdentifier): LooseLiteral<TimeZoneName | TimeZoneIdentifier>;
164
+ $getNativeTimeZoneName(tzId?: $TimeZoneIdentifier): LooseLiteral<TimeZoneName | $TimeZoneIdentifier>;
165
165
  /**
166
166
  * @instance Retrieves the IANA time zone identifier (e.g., `"Asia/Dhaka"`, `"Africa/Harare"`) for the local system's current time zone.
167
167
  *
@@ -171,7 +171,7 @@ export declare class Chronos {
171
171
  *
172
172
  * @returns The local system's IANA time zone identifier.
173
173
  */
174
- $getNativeTimeZoneId(): TimeZoneIdentifier;
174
+ $getNativeTimeZoneId(): $TimeZoneIdentifier;
175
175
  /** Gets the full year of the date. */
176
176
  get year(): number;
177
177
  /** Gets the month (0-11) of the date. */
@@ -246,7 +246,7 @@ export declare class Chronos {
246
246
  /**
247
247
  * @instance Formats the date into a predefined strict string format using local time or UTC.
248
248
  *
249
- * @remarks Offers `over 26,500` predefined formats with full IntelliSense support.
249
+ * @remarks Offers `over 21,300` predefined formats with full IntelliSense support.
250
250
  *
251
251
  * @param format - The desired format string. Defaults to `'dd, mmm DD, YYYY HH:mm:ss'`
252
252
  * (e.g., `'Sun, Apr 06, 2025 16:11:55'`).
@@ -1,5 +1,5 @@
1
1
  import type { Numeric } from '../types/index';
2
- import type { ClockTime, TimeZoneIdentifier, UTCOffset } from './types';
2
+ import type { $TimeZoneIdentifier, ClockTime, UTCOffset } from './types';
3
3
  /**
4
4
  * * Checks if the provided value is a valid time string in "HH:MM" format.
5
5
  *
@@ -15,11 +15,11 @@ export declare function isValidTime(value: unknown): value is ClockTime;
15
15
  */
16
16
  export declare function isValidUTCOffset(value: unknown): value is UTCOffset;
17
17
  /**
18
- * * Checks if the provided value is a valid timezone identifier from {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones IANA TZ Database} (e.g. `"Africa/Harare"`).
18
+ * * Checks if the provided value is a valid timezone identifier (excluding `'Factory'`) from {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones IANA TZ Database} (e.g. `"Africa/Harare"`).
19
19
  * @param value Timezone id to check.
20
20
  * @returns `true` if the value is a valid timezone id, `false` otherwise.
21
21
  */
22
- export declare function isValidTimeZoneId(value: unknown): value is TimeZoneIdentifier;
22
+ export declare function isValidTimeZoneId(value: unknown): value is $TimeZoneIdentifier;
23
23
  /**
24
24
  * * Checks if the year is a leap year.
25
25
  *
@@ -7,7 +7,7 @@ declare module '../Chronos' {
7
7
  /**
8
8
  * @instance Creates a new instance of `Chronos` for the specified time zone identifier.
9
9
  *
10
- * @remarks Using time zone identifier to create time zone instance is the best option.
10
+ * @remarks Using time zone identifier to create time zone instance is the best option as it extract info from {@link Intl} API.
11
11
  *
12
12
  * @param tzId - Time zone identifier (e.g., `'Africa/Harare'`). See: {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones IANA TZ Database on Wikipedia}.
13
13
  * @returns A new instance of `Chronos` with time in the given time zone identifier. Invalid input sets time-zone to `UTC`.
@@ -16,14 +16,14 @@ declare module '../Chronos' {
16
16
  /**
17
17
  * @instance Creates a new instance of `Chronos` for the specified abbreviated time zone name.
18
18
  *
19
- * @remarks Use abbreviated time zone name to create time zone instance only when you can't figure out the time zone identifier.
19
+ * @remarks Use abbreviated time zone name to create time zone instance only when you can't figure out the time zone identifier {@link TimeZoneIdentifier}.
20
20
  *
21
21
  * @param zone - Standard time zone abbreviation (e.g., `'IST'`, `'UTC'`, `'EST'` etc.). See: {@link https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations Time zone abbreviations on Wikipedia}.
22
22
  * @returns A new instance of `Chronos` with time in the given time zone abbreviation. Invalid input sets time-zone to `UTC`.
23
23
  */
24
24
  timeZone(zone: TimeZone): ChronosConstructor;
25
25
  /**
26
- * @instance Creates a new instance of `Chronos` for the specified utc offset.
26
+ * @instance Creates a new instance of `Chronos` for the specified UTC offset.
27
27
  *
28
28
  * @remarks Use UTC offset only to create a fictional/unlisted time zone instance.
29
29
  *
@@ -31,6 +31,18 @@ declare module '../Chronos' {
31
31
  * @returns A new instance of `Chronos` with time in the given utc offset. Invalid input sets time-zone to `UTC`.
32
32
  */
33
33
  timeZone(utc: UTCOffset): ChronosConstructor;
34
+ /**
35
+ * @instance Creates a new instance of `Chronos` for the specified time zone id, abbreviation or UTC offset.
36
+ *
37
+ * @remarks
38
+ * - Using time zone identifier to create time zone instance is the best option as it extract info from {@link Intl} API.
39
+ * - Use abbreviated time zone name to create time zone instance only when you can't figure out the time zone identifier.
40
+ * - Use UTC offset only to create a fictional/unlisted time zone instance.
41
+ *
42
+ * @param tz - A time zone identifier ({@link TimeZoneIdentifier}), time zone abbreviation {@link TimeZone}, or UTC offset {@link UTCOffset}.
43
+ * @returns A new instance of `Chronos` with time in the given parameter. Invalid input sets time zone to `UTC`.
44
+ */
45
+ timeZone(tz: TimeZoneIdentifier | TimeZone | UTCOffset): ChronosConstructor;
34
46
  /**
35
47
  * @instance Returns the current time zone name as a full descriptive string (e.g. `"Bangladesh Standard Time"`).
36
48
  *
@@ -2861,6 +2861,10 @@ export declare const TIME_ZONE_IDS: Readonly<{
2861
2861
  readonly tzName: "Central European Time";
2862
2862
  readonly offset: "UTC+01:00";
2863
2863
  };
2864
+ readonly Factory: {
2865
+ readonly tzName: undefined;
2866
+ readonly offset: "UTC+00:00";
2867
+ };
2864
2868
  readonly GB: {
2865
2869
  readonly tzName: "Greenwich Mean Time";
2866
2870
  readonly offset: "UTC+00:00";
@@ -50,13 +50,13 @@ export interface GreetingConfigs {
50
50
  /** Time zone details object */
51
51
  export type TimeZoneDetails = {
52
52
  /** IANA time zone identifier */
53
- tzIdentifier: LooseLiteral<TimeZoneIdentifier>;
53
+ tzIdentifier: $TimeZoneIdentifier;
54
54
  /** Long localized form (e.g., `'Pacific Standard Time'`, `'Nordamerikanische Westküsten-Normalzeit'`) */
55
- tzNameLong?: LooseLiteral<TimeZoneName>;
55
+ tzNameLong: LooseLiteral<TimeZoneName> | undefined;
56
56
  /** Long generic non-location format (e.g.: `'Pacific Time'`, `'Nordamerikanische Westküstenzeit'`) */
57
- tzNameLongGeneric?: LooseLiteral<TimeZoneName>;
57
+ tzNameLongGeneric: LooseLiteral<TimeZoneName> | undefined;
58
58
  /** Long localized GMT format, prefixed with `"GMT"` (e.g., `"GMT-08:00"`) */
59
- tzNameLongOffset?: LooseLiteral<`GMT${$UTCOffset}`>;
59
+ tzNameLongOffset: LooseLiteral<`GMT${$UTCOffset}`> | undefined;
60
60
  };
61
61
  /** Name of time unit from `year` to `millisecond` */
62
62
  export type TimeUnit = 'year' | 'month' | 'day' | 'week' | 'hour' | 'minute' | 'second' | 'millisecond';
@@ -89,14 +89,14 @@ export type DateParts = `${MonthDate} ${Exclude<Month, 'M' | 'MM'>}` | `${Exclud
89
89
  /** Standard Time Formats */
90
90
  export type TimeParts = `${Exclude<Hour, 'h' | 'hh' | 'H'>}:${Exclude<Minute, 'm'>}` | `${Exclude<Hour, 'H' | 'HH' | 'h'>}:${Exclude<Minute, 'm'>} ${TimeFormats}` | `${Exclude<Hour, 'h' | 'hh' | 'H'>}:${Exclude<Minute, 'm'>}:${Exclude<Second, 's'>}` | `${Exclude<Hour, 'H' | 'HH' | 'h'>}:${Exclude<Minute, 'm'>}:${Exclude<Second, 's'>} ${TimeFormats}` | `${Exclude<Hour, 'h' | 'hh' | 'H'>}:${Exclude<Minute, 'm'>}:${Exclude<Second, 's'>}:${Exclude<Millisecond, 'ms'>}` | `${Exclude<Hour, 'H' | 'HH' | 'h'>}:${Exclude<Minute, 'm'>}:${Exclude<Second, 's'>}:${Exclude<Millisecond, 'ms'>} ${TimeFormats}`;
91
91
  type DateTimeISO = 'YYYY-MM-DDTHH:mm:ss.mssZZ';
92
- type DateTimeConnector = ' ' | ', ' | '; ' | ' - ' | 'T';
92
+ type DateTimeConnector = ' ' | ', ' | '; ' | ' - ';
93
93
  /** Pre-defined literal types for formatting date and time. Optionally can pass any string. */
94
94
  export type StrictFormat = LooseLiteral<DateTimeISO | DateParts | TimeParts | `${DateParts}${DateTimeConnector}${TimeParts}`>;
95
95
  /** Locale arguments for `toLocaleString` method. Includes `BCP47` tags and `Intl.Locale`. */
96
96
  export type LocalesArguments = LocaleCode | Intl.Locale | Array<LocaleCode | Intl.Locale>;
97
97
  /** Format options for `toLocaleString` method. Extends `Intl.DateTimeFormatOptions `to update `timeZone` option. */
98
98
  export interface DateTimeFormatOptions extends Intl.DateTimeFormatOptions {
99
- timeZone?: TimeZoneIdentifier;
99
+ timeZone?: $TimeZoneIdentifier;
100
100
  }
101
101
  /** Iterable `Chronos` object properties */
102
102
  export interface ChronosObject {
@@ -172,7 +172,7 @@ export interface ChronosInternals {
172
172
  * @param tzTracker Optional tracker to identify the instance created by {@link timeZone} method.
173
173
  * @returns The `Chronos` instance with the specified origin and other properties.
174
174
  */
175
- withOrigin(instance: Chronos, method: PluginMethods, offset?: UTCOffset, tzName?: string, tzId?: TimeZoneId, tzTracker?: TimeZoneIdentifier | TimeZone | UTCOffset): Chronos;
175
+ withOrigin(instance: Chronos, method: PluginMethods, offset?: UTCOffset, tzName?: LooseLiteral<TimeZoneName>, tzId?: TimeZoneId, tzTracker?: $TimeZoneIdentifier | TimeZone | UTCOffset): Chronos;
176
176
  /**
177
177
  * * Access to `#toNewDate` private method
178
178
  * * Creates a new `Date` object from a Chronos input
@@ -227,14 +227,16 @@ export type ChronosInput = number | string | Date | Chronos;
227
227
  export type ChronosStaticKey = keyof ChronosStatics;
228
228
  /** Key of {@link TIME_ZONE_LABELS} ({@link UTCOffset}) */
229
229
  export type $TZLabelKey = keyof typeof TIME_ZONE_LABELS;
230
- /** Abbreviated time-zone names (from {@link https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations time zone abbreviations on Wikipedia}) */
230
+ /** Abbreviated time zone names (from {@link https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations time zone abbreviations on Wikipedia}). */
231
231
  export type TimeZone = keyof typeof TIME_ZONES;
232
232
  /** Full time zone names from Wikipedia and IANA time zone database. */
233
- export type TimeZoneName = NonNullable<(typeof TIME_ZONE_LABELS)[$TZLabelKey] | (typeof TIME_ZONES)[TimeZone]['tzName'] | (typeof TIME_ZONE_IDS)[TimeZoneIdentifier]['tzName']>;
234
- /** Timezone identifier (from {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones IANA TZ Database on Wikipedia}) */
235
- export type TimeZoneIdentifier = keyof typeof TIME_ZONE_IDS;
236
- /** Timezone identifier, array of timezone identifiers or UTC offset. */
237
- export type TimeZoneId = TimeZoneIdentifier | TimeZoneIdentifier[] | UTCOffset;
233
+ export type TimeZoneName = NonNullable<(typeof TIME_ZONE_LABELS)[$TZLabelKey] | (typeof TIME_ZONES)[TimeZone]['tzName'] | (typeof TIME_ZONE_IDS)[$TimeZoneIdentifier]['tzName']>;
234
+ /** Time zone identifier (from {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones IANA TZ Database on Wikipedia}) excluding `'Factory'`. */
235
+ export type $TimeZoneIdentifier = Exclude<keyof typeof TIME_ZONE_IDS, 'Factory'>;
236
+ /** Time zone identifier (from {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones IANA TZ Database on Wikipedia}) excluding `'Factory'` & abbreviations present in {@link TimeZone}. */
237
+ export type TimeZoneIdentifier = Exclude<$TimeZoneIdentifier, TimeZone>;
238
+ /** Time zone identifier, array of timezone identifiers or UTC offset. */
239
+ export type TimeZoneId = $TimeZoneIdentifier | $TimeZoneIdentifier[] | UTCOffset;
238
240
  /** Positive UTC hours */
239
241
  export type PositiveUTCHour = `+0${Enumerate<10>}` | `+${NumberRange<10, 14>}`;
240
242
  /** Negative UTC hours */
@@ -1,5 +1,5 @@
1
1
  import type { Numeric } from '../types/index';
2
- import type { ClockTime, HourMinutes, TimeZoneDetails, TimeZoneIdentifier, UTCOffset } from './types';
2
+ import type { $TimeZoneIdentifier, ClockTime, HourMinutes, TimeZoneDetails, UTCOffset } from './types';
3
3
  /**
4
4
  * * Extracts the hour and minute from a time string in `HH:MM` or `-HH:MM` format.
5
5
  *
@@ -56,9 +56,9 @@ export declare function convertMinutesToTime(minutes: Numeric): HourMinutes;
56
56
  */
57
57
  export declare function formatUTCOffset(minutes: Numeric): UTCOffset;
58
58
  /**
59
- * * Retrieves comprehensive time zone details using the {@link Intl} API.
60
- * @param tzId Optional timezone identifier; defaults to the system timezone.
59
+ * * Retrieves comprehensive time zone details using the {@link Intl.DateTimeFormat} API.
60
+ * @param tzId Optional timezone identifier. Defaults to the system timezone.
61
61
  * @param date Optional date for which to resolve the information.
62
62
  * @returns Object containing time zone identifier, names, and offset.
63
63
  */
64
- export declare function getTimeZoneDetails(tzId?: TimeZoneIdentifier, date?: Date): TimeZoneDetails;
64
+ export declare function getTimeZoneDetails(tzId?: $TimeZoneIdentifier, date?: Date): TimeZoneDetails;
@@ -156,12 +156,17 @@ export class Chronos {
156
156
  return instance;
157
157
  }
158
158
  #getNativeTzName(tzId) {
159
- const tzDetails = new Intl.DateTimeFormat('en', {
160
- timeZone: tzId,
161
- timeZoneName: 'long',
162
- }).formatToParts(this.#date);
163
- const tzPart = tzDetails.find((p) => p.type === 'timeZoneName');
164
- return tzPart?.value;
159
+ try {
160
+ const tzDetails = new Intl.DateTimeFormat('en', {
161
+ timeZone: tzId,
162
+ timeZoneName: 'long',
163
+ }).formatToParts(this.#date);
164
+ const tzPart = tzDetails.find((p) => p.type === 'timeZoneName');
165
+ return tzPart?.value;
166
+ }
167
+ catch {
168
+ return undefined;
169
+ }
165
170
  }
166
171
  #format(format, useUTC = false) {
167
172
  const year = useUTC ? this.#date.getUTCFullYear() : this.#date.getFullYear();
@@ -16,7 +16,7 @@ export function isValidUTCOffset(value) {
16
16
  return isString(value) ? /^UTC[+-]?\d{1,2}:\d{2}$/.test(value) : false;
17
17
  }
18
18
  export function isValidTimeZoneId(value) {
19
- return isString(value) ? value in TIME_ZONE_IDS : false;
19
+ return isString(value) ? value !== 'Factory' && value in TIME_ZONE_IDS : false;
20
20
  }
21
21
  export function isLeapYear(year) {
22
22
  const $year = normalizeNumber(year);
@@ -1,18 +1,18 @@
1
1
  import { INTERNALS } from '../constants.js';
2
- import { isValidTimeZoneId, isValidUTCOffset } from '../guards.js';
3
- import { TIME_ZONES, TIME_ZONE_IDS, TIME_ZONE_LABELS } from '../timezone.js';
4
- import { getTimeZoneDetails, extractMinutesFromUTC } from '../utils.js';
2
+ import { isValidUTCOffset } from '../guards.js';
3
+ import { TIME_ZONES, TIME_ZONE_LABELS } from '../timezone.js';
4
+ import { extractMinutesFromUTC } from '../utils.js';
5
5
  export const timeZonePlugin = (ChronosClass) => {
6
6
  const { internalDate: $Date, withOrigin } = ChronosClass[INTERNALS];
7
+ const TZ_IDS = Intl.supportedValuesOf('timeZone');
7
8
  const _isGMT = (factor) => {
8
9
  return factor === 'UTC+00:00' || factor === 'UTC-00:00';
9
10
  };
10
- const TZ_NAME_ABBR_MAP = new Map(Object.entries(TIME_ZONES).map(([tzAbbr, { offset, tzName }]) => [
11
- offset,
12
- { tzAbbr, tzName },
13
- ]));
14
11
  const _isLabelKey = (offset) => {
15
- return offset in TIME_ZONE_LABELS;
12
+ return offset ? offset in TIME_ZONE_LABELS : false;
13
+ };
14
+ const _isValidTzAbbr = (tz) => {
15
+ return tz in TIME_ZONES;
16
16
  };
17
17
  const _resolveTzName = (offset) => {
18
18
  if (_isLabelKey(offset)) {
@@ -20,6 +20,51 @@ export const timeZonePlugin = (ChronosClass) => {
20
20
  }
21
21
  return undefined;
22
22
  };
23
+ const _getTimeZoneDetails = (tzId, date) => {
24
+ const TZ_NAME_TYPES = ['long', 'longOffset'];
25
+ const obj = { tzId };
26
+ for (const type of TZ_NAME_TYPES) {
27
+ const key = type === 'long' ? 'tzName' : 'offset';
28
+ try {
29
+ const parts = new Intl.DateTimeFormat('en', {
30
+ timeZone: tzId,
31
+ timeZoneName: type,
32
+ }).formatToParts(date);
33
+ const tzPart = parts.find((p) => p.type === 'timeZoneName');
34
+ const value = type === 'longOffset' ?
35
+ tzPart?.value === 'GMT' ?
36
+ 'UTC+00:00'
37
+ : tzPart?.value?.replace(/^GMT/, 'UTC')
38
+ : tzPart?.value;
39
+ obj[key] = value;
40
+ }
41
+ catch {
42
+ obj[key] = undefined;
43
+ }
44
+ }
45
+ return obj;
46
+ };
47
+ const TZ_ID_MAP = new Map(TZ_IDS.reduce((tzIds, id) => {
48
+ const { offset } = _getTimeZoneDetails(id);
49
+ if (offset) {
50
+ const arr = tzIds.get(offset) ?? [];
51
+ arr.push(id);
52
+ tzIds.set(offset, arr);
53
+ }
54
+ return tzIds;
55
+ }, new Map()));
56
+ const TZ_NAME_ABBR_MAP = new Map(Object.entries(TIME_ZONES).map(([tzAbbr, { offset, tzName }]) => [
57
+ offset,
58
+ { tzAbbr, tzName },
59
+ ]));
60
+ const _getTimeZoneId = (utc) => {
61
+ const tzIds = TZ_ID_MAP.get(utc);
62
+ if (!tzIds || tzIds?.length === 0)
63
+ return undefined;
64
+ if (tzIds?.length === 1)
65
+ return tzIds[0];
66
+ return tzIds;
67
+ };
23
68
  const _getTimeZoneName = (zone, date) => {
24
69
  if (_isGMT(zone))
25
70
  return 'Greenwich Mean Time';
@@ -30,34 +75,14 @@ export const timeZonePlugin = (ChronosClass) => {
30
75
  }
31
76
  return tzName;
32
77
  }
33
- else if (isValidTimeZoneId(zone)) {
34
- const { offset, tzName } = TIME_ZONE_IDS[zone];
35
- const { tzNameLongOffset, tzNameLong } = getTimeZoneDetails(zone, date);
36
- const convertedOffset = tzNameLongOffset?.replace(/^GMT/, 'UTC') ?? '';
37
- const resolvedName = _resolveTzName(offset);
38
- const priorityName = convertedOffset === offset ? tzNameLong : resolvedName;
39
- return tzName || priorityName || resolvedName || tzNameLong;
78
+ else if (_isValidTzAbbr(zone)) {
79
+ return TIME_ZONES[zone].tzName;
40
80
  }
41
81
  else {
42
- return zone in TIME_ZONES ?
43
- TIME_ZONES[zone].tzName
44
- : _resolveTzName(TIME_ZONES[zone]?.offset);
82
+ const { offset, tzName } = _getTimeZoneDetails(zone, date);
83
+ return tzName || _resolveTzName(offset);
45
84
  }
46
85
  };
47
- const TZ_ID_MAP = new Map(Object.entries(TIME_ZONE_IDS).reduce((acc, [id, { offset }]) => {
48
- const arr = acc.get(offset) ?? [];
49
- arr.push(id);
50
- acc.set(offset, arr);
51
- return acc;
52
- }, new Map()));
53
- const _getTimeZoneId = (utc) => {
54
- const tzIds = TZ_ID_MAP.get(utc);
55
- if (!tzIds || tzIds?.length === 0)
56
- return undefined;
57
- if (tzIds?.length === 1)
58
- return tzIds[0];
59
- return tzIds;
60
- };
61
86
  ChronosClass.prototype.timeZone = function (zone) {
62
87
  let offset;
63
88
  let tzId;
@@ -65,13 +90,13 @@ export const timeZonePlugin = (ChronosClass) => {
65
90
  offset = zone;
66
91
  tzId = _getTimeZoneId(offset) || offset;
67
92
  }
68
- else if (isValidTimeZoneId(zone)) {
69
- offset = TIME_ZONE_IDS[zone].offset;
70
- tzId = zone;
93
+ else if (_isValidTzAbbr(zone)) {
94
+ offset = TIME_ZONES[zone].offset;
95
+ tzId = _getTimeZoneId(offset) || offset;
71
96
  }
72
97
  else {
73
- offset = zone in TIME_ZONES ? TIME_ZONES[zone].offset : TIME_ZONES['UTC'].offset;
74
- tzId = _getTimeZoneId(offset) || offset;
98
+ offset = _getTimeZoneDetails(zone, $Date(this)).offset || TIME_ZONES['UTC'].offset;
99
+ tzId = zone;
75
100
  }
76
101
  const $zone = zone || offset;
77
102
  const tzName = _getTimeZoneName($zone, $Date(this)) ?? offset;
@@ -118,7 +143,7 @@ export const timeZonePlugin = (ChronosClass) => {
118
143
  const zone = _getTimeZoneName(tzMapKey, $Date(this)) ?? UTC;
119
144
  if (TZ_ABBR_CACHE.has(`name-${zone}`))
120
145
  return TZ_ABBR_CACHE.get(zone);
121
- const customAbbr = isValidUTCOffset(zone) || isValidTimeZoneId(zone) ? zone : _abbreviate(zone);
146
+ const customAbbr = isValidUTCOffset(zone) ? zone : _abbreviate(zone);
122
147
  TZ_ABBR_CACHE.set(`name-${zone}`, customAbbr);
123
148
  return customAbbr;
124
149
  };
@@ -2858,6 +2858,10 @@ export const TIME_ZONE_IDS = /* @__PURE__ */ Object.freeze({
2858
2858
  tzName: 'Central European Time',
2859
2859
  offset: 'UTC+01:00',
2860
2860
  },
2861
+ Factory: {
2862
+ tzName: undefined,
2863
+ offset: 'UTC+00:00',
2864
+ },
2861
2865
  GB: {
2862
2866
  tzName: 'Greenwich Mean Time',
2863
2867
  offset: 'UTC+00:00',
@@ -34,13 +34,18 @@ export function getTimeZoneDetails(tzId, date) {
34
34
  const $tzId = tzId || Intl.DateTimeFormat().resolvedOptions().timeZone;
35
35
  const obj = { tzIdentifier: $tzId };
36
36
  for (const type of TZ_NAME_TYPES) {
37
- const parts = new Intl.DateTimeFormat('en', {
38
- timeZone: $tzId,
39
- timeZoneName: type,
40
- }).formatToParts(date);
41
- const tzPart = parts.find((p) => p.type === 'timeZoneName');
42
37
  const key = `tzName${type[0].toUpperCase()}${type.slice(1)}`;
43
- obj[key] = tzPart?.value;
38
+ try {
39
+ const parts = new Intl.DateTimeFormat('en', {
40
+ timeZone: $tzId,
41
+ timeZoneName: type,
42
+ }).formatToParts(date);
43
+ const tzPart = parts.find((p) => p.type === 'timeZoneName');
44
+ obj[key] = tzPart?.value;
45
+ }
46
+ catch {
47
+ obj[key] = undefined;
48
+ }
44
49
  }
45
50
  return obj;
46
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nhb-toolbox",
3
- "version": "4.26.45",
3
+ "version": "4.26.50",
4
4
  "description": "A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",