@osovitny/anatoly 3.17.6 → 3.17.8

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.
@@ -204,6 +204,228 @@ class Convert {
204
204
  }
205
205
  }
206
206
 
207
+ /*
208
+ <file>
209
+ Project:
210
+ @osovitny/anatoly
211
+
212
+ Authors:
213
+ Vadim Osovitny vadim@osovitny.com
214
+ Anatoly Osovitny anatoly@osovitny.com
215
+
216
+ Created:
217
+ 10 Feb 2024
218
+
219
+ Copyright (c) 2016-2022 Osovitny Inc. All rights reserved.
220
+ </file>
221
+ */
222
+ /**
223
+ * Returns the [year, month, day, hour, minute, seconds] tokens of the provided
224
+ * `date` as it will be rendered in the `timeZone`.
225
+ */
226
+ function tzTokenizeDate(date, timeZone) {
227
+ var dtf = getDateTimeFormat(timeZone);
228
+ return dtf.formatToParts ? partsOffset(dtf, date) : hackyOffset(dtf, date);
229
+ }
230
+ var typeToPos = {
231
+ year: 0,
232
+ month: 1,
233
+ day: 2,
234
+ hour: 3,
235
+ minute: 4,
236
+ second: 5,
237
+ };
238
+ function partsOffset(dtf, date) {
239
+ try {
240
+ var formatted = dtf.formatToParts(date);
241
+ var filled = [];
242
+ for (var i = 0; i < formatted.length; i++) {
243
+ var pos = typeToPos[formatted[i].type];
244
+ if (pos >= 0) {
245
+ filled[pos] = parseInt(formatted[i].value, 10);
246
+ }
247
+ }
248
+ return filled;
249
+ }
250
+ catch (error) {
251
+ if (error instanceof RangeError) {
252
+ return [NaN];
253
+ }
254
+ throw error;
255
+ }
256
+ }
257
+ function hackyOffset(dtf, date) {
258
+ var formatted = dtf.format(date).replace(/\u200E/g, '');
259
+ var parsed = /(\d+)\/(\d+)\/(\d+),? (\d+):(\d+):(\d+)/.exec(formatted);
260
+ // var [, fMonth, fDay, fYear, fHour, fMinute, fSecond] = parsed
261
+ // return [fYear, fMonth, fDay, fHour, fMinute, fSecond]
262
+ return [parsed[3], parsed[1], parsed[2], parsed[4], parsed[5], parsed[6]];
263
+ }
264
+ // Get a cached Intl.DateTimeFormat instance for the IANA `timeZone`. This can be used
265
+ // to get deterministic local date/time output according to the `en-US` locale which
266
+ // can be used to extract local time parts as necessary.
267
+ var dtfCache = {};
268
+ function getDateTimeFormat(timeZone) {
269
+ if (!dtfCache[timeZone]) {
270
+ // New browsers use `hourCycle`, IE and Chrome <73 does not support it and uses `hour12`
271
+ var testDateFormatted = new Intl.DateTimeFormat('en-US', {
272
+ hour12: false,
273
+ timeZone: 'America/New_York',
274
+ year: 'numeric',
275
+ month: 'numeric',
276
+ day: '2-digit',
277
+ hour: '2-digit',
278
+ minute: '2-digit',
279
+ second: '2-digit',
280
+ }).format(new Date('2014-06-25T04:00:00.123Z'));
281
+ var hourCycleSupported = testDateFormatted === '06/25/2014, 00:00:00' ||
282
+ testDateFormatted === '06/25/2014 00:00:00';
283
+ dtfCache[timeZone] = hourCycleSupported
284
+ ? new Intl.DateTimeFormat('en-US', {
285
+ hour12: false,
286
+ timeZone: timeZone,
287
+ year: 'numeric',
288
+ month: 'numeric',
289
+ day: '2-digit',
290
+ hour: '2-digit',
291
+ minute: '2-digit',
292
+ second: '2-digit',
293
+ })
294
+ : new Intl.DateTimeFormat('en-US', {
295
+ hourCycle: 'h23',
296
+ timeZone: timeZone,
297
+ year: 'numeric',
298
+ month: 'numeric',
299
+ day: '2-digit',
300
+ hour: '2-digit',
301
+ minute: '2-digit',
302
+ second: '2-digit',
303
+ });
304
+ }
305
+ return dtfCache[timeZone];
306
+ }
307
+
308
+ /*
309
+ <file>
310
+ Project:
311
+ @osovitny/anatoly
312
+
313
+ Authors:
314
+ Vadim Osovitny vadim@osovitny.com
315
+ Anatoly Osovitny anatoly@osovitny.com
316
+
317
+ Created:
318
+ 10 Feb 2024
319
+
320
+ Copyright (c) 2016-2022 Osovitny Inc. All rights reserved.
321
+ </file>
322
+ */
323
+ function tzParseTimezone(timezoneString, date, isUtcDate) {
324
+ var token;
325
+ var absoluteOffset;
326
+ // Empty string
327
+ if (!timezoneString) {
328
+ return 0;
329
+ }
330
+ // Z
331
+ token = patterns.timezoneZ.exec(timezoneString);
332
+ if (token) {
333
+ return 0;
334
+ }
335
+ var hours;
336
+ // ±hh
337
+ token = patterns.timezoneHH.exec(timezoneString);
338
+ if (token) {
339
+ hours = parseInt(token[1], 10);
340
+ if (!validateTimezone(hours)) {
341
+ return NaN;
342
+ }
343
+ return -(hours * MILLISECONDS_IN_HOUR);
344
+ }
345
+ // ±hh:mm or ±hhmm
346
+ token = patterns.timezoneHHMM.exec(timezoneString);
347
+ if (token) {
348
+ hours = parseInt(token[1], 10);
349
+ var minutes = parseInt(token[2], 10);
350
+ if (!validateTimezone(hours, minutes)) {
351
+ return NaN;
352
+ }
353
+ absoluteOffset = Math.abs(hours) * MILLISECONDS_IN_HOUR + minutes * MILLISECONDS_IN_MINUTE;
354
+ return hours > 0 ? -absoluteOffset : absoluteOffset;
355
+ }
356
+ // IANA time zone
357
+ if (isValidTimezoneIANAString(timezoneString)) {
358
+ date = new Date(date || Date.now());
359
+ var utcDate = isUtcDate ? date : toUtcDate(date);
360
+ var offset = calcOffset(utcDate, timezoneString);
361
+ var fixedOffset = isUtcDate ? offset : fixOffset(date, offset, timezoneString);
362
+ return -fixedOffset;
363
+ }
364
+ return NaN;
365
+ }
366
+ var MILLISECONDS_IN_HOUR = 3600000;
367
+ var MILLISECONDS_IN_MINUTE = 60000;
368
+ var patterns = {
369
+ timezone: /([Z+-].*)$/,
370
+ timezoneZ: /^(Z)$/,
371
+ timezoneHH: /^([+-]\d{2})$/,
372
+ timezoneHHMM: /^([+-]\d{2}):?(\d{2})$/,
373
+ };
374
+ function newDateUTC(fullYear, month, day, hour, minute, second, millisecond) {
375
+ var utcDate = new Date(0);
376
+ utcDate.setUTCFullYear(fullYear, month, day);
377
+ utcDate.setUTCHours(hour, minute, second, millisecond);
378
+ return utcDate;
379
+ }
380
+ function toUtcDate(date) {
381
+ return newDateUTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
382
+ }
383
+ function calcOffset(date, timezoneString) {
384
+ var tokens = tzTokenizeDate(date, timezoneString);
385
+ // ms dropped because it's not provided by tzTokenizeDate
386
+ var asUTC = newDateUTC(tokens[0], tokens[1] - 1, tokens[2], tokens[3] % 24, tokens[4], tokens[5], 0).getTime();
387
+ var asTS = date.getTime();
388
+ var over = asTS % 1000;
389
+ asTS -= over >= 0 ? over : 1000 + over;
390
+ return asUTC - asTS;
391
+ }
392
+ function fixOffset(date, offset, timezoneString) {
393
+ var localTS = date.getTime();
394
+ // Our UTC time is just a guess because our offset is just a guess
395
+ var utcGuess = localTS - offset;
396
+ // Test whether the zone matches the offset for this ts
397
+ var o2 = calcOffset(new Date(utcGuess), timezoneString);
398
+ // If so, offset didn't change, and we're done
399
+ if (offset === o2) {
400
+ return offset;
401
+ }
402
+ // If not, change the ts by the difference in the offset
403
+ utcGuess -= o2 - offset;
404
+ // If that gives us the local time we want, we're done
405
+ var o3 = calcOffset(new Date(utcGuess), timezoneString);
406
+ if (o2 === o3) {
407
+ return o2;
408
+ }
409
+ // If it's different, we're in a hole time. The offset has changed, but we don't adjust the time
410
+ return Math.max(o2, o3);
411
+ }
412
+ function validateTimezone(hours, minutes = null) {
413
+ return -23 <= hours && hours <= 23 && (minutes == null || (0 <= minutes && minutes <= 59));
414
+ }
415
+ var validIANATimezoneCache = {};
416
+ function isValidTimezoneIANAString(timeZoneString) {
417
+ if (validIANATimezoneCache[timeZoneString])
418
+ return true;
419
+ try {
420
+ new Intl.DateTimeFormat(undefined, { timeZone: timeZoneString });
421
+ validIANATimezoneCache[timeZoneString] = true;
422
+ return true;
423
+ }
424
+ catch (error) {
425
+ return false;
426
+ }
427
+ }
428
+
207
429
  /*
208
430
  <file>
209
431
  Project:
@@ -219,6 +441,11 @@ class Convert {
219
441
  Source:
220
442
  https://github.com/date-fns/date-fns/blob/main/src/toDate/index.ts
221
443
 
444
+ tz:
445
+ https://www.npmjs.com/package/date-fns-tz
446
+ https://github.com/marnusw/date-fns-tz/blob/master/src/utcToZonedTime/index.js
447
+ https://github.com/marnusw/date-fns-tz/blob/master/src/_lib/tzParseTimezone/index.js
448
+
222
449
  Copyright (c) 2016-2022 Osovitny Inc. All rights reserved.
223
450
  </file>
224
451
  */
@@ -236,6 +463,27 @@ class DateConvert {
236
463
  return new Date(NaN);
237
464
  }
238
465
  }
466
+ static utcToLocal(dirtyDate) {
467
+ if (typeof dirtyDate === 'string') {
468
+ if (dirtyDate.indexOf("T") > -1) {
469
+ dirtyDate = dirtyDate.replace("T", " ");
470
+ }
471
+ if (dirtyDate.indexOf("Z") == -1) {
472
+ dirtyDate = dirtyDate + "Z";
473
+ }
474
+ }
475
+ let browserTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
476
+ if (browserTimeZone) {
477
+ let date = DateConvert.toDate(dirtyDate);
478
+ let offsetMilliseconds = tzParseTimezone(browserTimeZone, date, true);
479
+ let d = new Date(date.getTime() - offsetMilliseconds);
480
+ let resultDate = new Date(0);
481
+ resultDate.setFullYear(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
482
+ resultDate.setHours(d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
483
+ return resultDate;
484
+ }
485
+ return new Date(dirtyDate);
486
+ }
239
487
  }
240
488
 
241
489
  /*
@@ -1716,258 +1964,6 @@ is = {
1716
1964
  };
1717
1965
  */
1718
1966
 
1719
- /*
1720
- <file>
1721
- Project:
1722
- @osovitny/anatoly
1723
-
1724
- Authors:
1725
- Vadim Osovitny vadim@osovitny.com
1726
- Anatoly Osovitny anatoly@osovitny.com
1727
-
1728
- Created:
1729
- 10 Feb 2024
1730
-
1731
- Copyright (c) 2016-2022 Osovitny Inc. All rights reserved.
1732
- </file>
1733
- */
1734
- /**
1735
- * Returns the [year, month, day, hour, minute, seconds] tokens of the provided
1736
- * `date` as it will be rendered in the `timeZone`.
1737
- */
1738
- function tzTokenizeDate(date, timeZone) {
1739
- var dtf = getDateTimeFormat(timeZone);
1740
- return dtf.formatToParts ? partsOffset(dtf, date) : hackyOffset(dtf, date);
1741
- }
1742
- var typeToPos = {
1743
- year: 0,
1744
- month: 1,
1745
- day: 2,
1746
- hour: 3,
1747
- minute: 4,
1748
- second: 5,
1749
- };
1750
- function partsOffset(dtf, date) {
1751
- try {
1752
- var formatted = dtf.formatToParts(date);
1753
- var filled = [];
1754
- for (var i = 0; i < formatted.length; i++) {
1755
- var pos = typeToPos[formatted[i].type];
1756
- if (pos >= 0) {
1757
- filled[pos] = parseInt(formatted[i].value, 10);
1758
- }
1759
- }
1760
- return filled;
1761
- }
1762
- catch (error) {
1763
- if (error instanceof RangeError) {
1764
- return [NaN];
1765
- }
1766
- throw error;
1767
- }
1768
- }
1769
- function hackyOffset(dtf, date) {
1770
- var formatted = dtf.format(date).replace(/\u200E/g, '');
1771
- var parsed = /(\d+)\/(\d+)\/(\d+),? (\d+):(\d+):(\d+)/.exec(formatted);
1772
- // var [, fMonth, fDay, fYear, fHour, fMinute, fSecond] = parsed
1773
- // return [fYear, fMonth, fDay, fHour, fMinute, fSecond]
1774
- return [parsed[3], parsed[1], parsed[2], parsed[4], parsed[5], parsed[6]];
1775
- }
1776
- // Get a cached Intl.DateTimeFormat instance for the IANA `timeZone`. This can be used
1777
- // to get deterministic local date/time output according to the `en-US` locale which
1778
- // can be used to extract local time parts as necessary.
1779
- var dtfCache = {};
1780
- function getDateTimeFormat(timeZone) {
1781
- if (!dtfCache[timeZone]) {
1782
- // New browsers use `hourCycle`, IE and Chrome <73 does not support it and uses `hour12`
1783
- var testDateFormatted = new Intl.DateTimeFormat('en-US', {
1784
- hour12: false,
1785
- timeZone: 'America/New_York',
1786
- year: 'numeric',
1787
- month: 'numeric',
1788
- day: '2-digit',
1789
- hour: '2-digit',
1790
- minute: '2-digit',
1791
- second: '2-digit',
1792
- }).format(new Date('2014-06-25T04:00:00.123Z'));
1793
- var hourCycleSupported = testDateFormatted === '06/25/2014, 00:00:00' ||
1794
- testDateFormatted === '06/25/2014 00:00:00';
1795
- dtfCache[timeZone] = hourCycleSupported
1796
- ? new Intl.DateTimeFormat('en-US', {
1797
- hour12: false,
1798
- timeZone: timeZone,
1799
- year: 'numeric',
1800
- month: 'numeric',
1801
- day: '2-digit',
1802
- hour: '2-digit',
1803
- minute: '2-digit',
1804
- second: '2-digit',
1805
- })
1806
- : new Intl.DateTimeFormat('en-US', {
1807
- hourCycle: 'h23',
1808
- timeZone: timeZone,
1809
- year: 'numeric',
1810
- month: 'numeric',
1811
- day: '2-digit',
1812
- hour: '2-digit',
1813
- minute: '2-digit',
1814
- second: '2-digit',
1815
- });
1816
- }
1817
- return dtfCache[timeZone];
1818
- }
1819
-
1820
- /*
1821
- <file>
1822
- Project:
1823
- @osovitny/anatoly
1824
-
1825
- Authors:
1826
- Vadim Osovitny vadim@osovitny.com
1827
- Anatoly Osovitny anatoly@osovitny.com
1828
-
1829
- Created:
1830
- 10 Feb 2024
1831
-
1832
- Copyright (c) 2016-2022 Osovitny Inc. All rights reserved.
1833
- </file>
1834
- */
1835
- function tzParseTimezone(timezoneString, date, isUtcDate) {
1836
- var token;
1837
- var absoluteOffset;
1838
- // Empty string
1839
- if (!timezoneString) {
1840
- return 0;
1841
- }
1842
- // Z
1843
- token = patterns.timezoneZ.exec(timezoneString);
1844
- if (token) {
1845
- return 0;
1846
- }
1847
- var hours;
1848
- // ±hh
1849
- token = patterns.timezoneHH.exec(timezoneString);
1850
- if (token) {
1851
- hours = parseInt(token[1], 10);
1852
- if (!validateTimezone(hours)) {
1853
- return NaN;
1854
- }
1855
- return -(hours * MILLISECONDS_IN_HOUR);
1856
- }
1857
- // ±hh:mm or ±hhmm
1858
- token = patterns.timezoneHHMM.exec(timezoneString);
1859
- if (token) {
1860
- hours = parseInt(token[1], 10);
1861
- var minutes = parseInt(token[2], 10);
1862
- if (!validateTimezone(hours, minutes)) {
1863
- return NaN;
1864
- }
1865
- absoluteOffset = Math.abs(hours) * MILLISECONDS_IN_HOUR + minutes * MILLISECONDS_IN_MINUTE;
1866
- return hours > 0 ? -absoluteOffset : absoluteOffset;
1867
- }
1868
- // IANA time zone
1869
- if (isValidTimezoneIANAString(timezoneString)) {
1870
- date = new Date(date || Date.now());
1871
- var utcDate = isUtcDate ? date : toUtcDate(date);
1872
- var offset = calcOffset(utcDate, timezoneString);
1873
- var fixedOffset = isUtcDate ? offset : fixOffset(date, offset, timezoneString);
1874
- return -fixedOffset;
1875
- }
1876
- return NaN;
1877
- }
1878
- var MILLISECONDS_IN_HOUR = 3600000;
1879
- var MILLISECONDS_IN_MINUTE = 60000;
1880
- var patterns = {
1881
- timezone: /([Z+-].*)$/,
1882
- timezoneZ: /^(Z)$/,
1883
- timezoneHH: /^([+-]\d{2})$/,
1884
- timezoneHHMM: /^([+-]\d{2}):?(\d{2})$/,
1885
- };
1886
- function newDateUTC(fullYear, month, day, hour, minute, second, millisecond) {
1887
- var utcDate = new Date(0);
1888
- utcDate.setUTCFullYear(fullYear, month, day);
1889
- utcDate.setUTCHours(hour, minute, second, millisecond);
1890
- return utcDate;
1891
- }
1892
- function toUtcDate(date) {
1893
- return newDateUTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
1894
- }
1895
- function calcOffset(date, timezoneString) {
1896
- var tokens = tzTokenizeDate(date, timezoneString);
1897
- // ms dropped because it's not provided by tzTokenizeDate
1898
- var asUTC = newDateUTC(tokens[0], tokens[1] - 1, tokens[2], tokens[3] % 24, tokens[4], tokens[5], 0).getTime();
1899
- var asTS = date.getTime();
1900
- var over = asTS % 1000;
1901
- asTS -= over >= 0 ? over : 1000 + over;
1902
- return asUTC - asTS;
1903
- }
1904
- function fixOffset(date, offset, timezoneString) {
1905
- var localTS = date.getTime();
1906
- // Our UTC time is just a guess because our offset is just a guess
1907
- var utcGuess = localTS - offset;
1908
- // Test whether the zone matches the offset for this ts
1909
- var o2 = calcOffset(new Date(utcGuess), timezoneString);
1910
- // If so, offset didn't change, and we're done
1911
- if (offset === o2) {
1912
- return offset;
1913
- }
1914
- // If not, change the ts by the difference in the offset
1915
- utcGuess -= o2 - offset;
1916
- // If that gives us the local time we want, we're done
1917
- var o3 = calcOffset(new Date(utcGuess), timezoneString);
1918
- if (o2 === o3) {
1919
- return o2;
1920
- }
1921
- // If it's different, we're in a hole time. The offset has changed, but we don't adjust the time
1922
- return Math.max(o2, o3);
1923
- }
1924
- function validateTimezone(hours, minutes = null) {
1925
- return -23 <= hours && hours <= 23 && (minutes == null || (0 <= minutes && minutes <= 59));
1926
- }
1927
- var validIANATimezoneCache = {};
1928
- function isValidTimezoneIANAString(timeZoneString) {
1929
- if (validIANATimezoneCache[timeZoneString])
1930
- return true;
1931
- try {
1932
- new Intl.DateTimeFormat(undefined, { timeZone: timeZoneString });
1933
- validIANATimezoneCache[timeZoneString] = true;
1934
- return true;
1935
- }
1936
- catch (error) {
1937
- return false;
1938
- }
1939
- }
1940
-
1941
- /*
1942
- <file>
1943
- Project:
1944
- @osovitny/anatoly
1945
-
1946
- Authors:
1947
- Vadim Osovitny vadim@osovitny.com
1948
- Anatoly Osovitny anatoly@osovitny.com
1949
-
1950
- Created:
1951
- 10 Feb 2024
1952
-
1953
- Source:
1954
- https://www.npmjs.com/package/date-fns-tz
1955
- https://github.com/marnusw/date-fns-tz/blob/master/src/utcToZonedTime/index.js
1956
- https://github.com/marnusw/date-fns-tz/blob/master/src/_lib/tzParseTimezone/index.js
1957
-
1958
- Copyright (c) 2016-2022 Osovitny Inc. All rights reserved.
1959
- </file>
1960
- */
1961
- function utcToZonedTime(dirtyDate, timeZone) {
1962
- let date = DateConvert.toDate(dirtyDate);
1963
- let offsetMilliseconds = tzParseTimezone(timeZone, date, true);
1964
- let d = new Date(date.getTime() - offsetMilliseconds);
1965
- let resultDate = new Date(0);
1966
- resultDate.setFullYear(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
1967
- resultDate.setHours(d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
1968
- return resultDate;
1969
- }
1970
-
1971
1967
  /*
1972
1968
  <file>
1973
1969
  Project:
@@ -2072,42 +2068,23 @@ class LocalizationService {
2072
2068
  }
2073
2069
  //UTC ---------------------------------------------------------------------BEGIN
2074
2070
  getUTCToLocalizedDate(value) {
2075
- return this.safeUtcToZonedTime(value, dateFormats.medium);
2071
+ return this.safeUtcToLocal(value, dateFormats.medium);
2076
2072
  }
2077
2073
  getUTCToLocalizedDateTime(value) {
2078
- return this.safeUtcToZonedTime(value, dateTimeFormats.medium);
2074
+ return this.safeUtcToLocal(value, dateTimeFormats.medium);
2079
2075
  }
2080
- safeUtcToZonedTime(date, conversionFormat = null) {
2076
+ safeUtcToLocal(date, conversionFormat = null) {
2081
2077
  if (!date) {
2082
2078
  return null;
2083
2079
  }
2084
2080
  let result = date;
2085
2081
  try {
2086
- if (typeof date === 'string') {
2087
- if (date.indexOf("T") > -1) {
2088
- date = date.replace("T", " ");
2089
- }
2090
- if (date.indexOf("Z") == -1) {
2091
- date = date + "Z";
2092
- }
2093
- }
2094
- let browserTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
2095
- if (browserTimeZone) {
2096
- if (conversionFormat) {
2097
- result = utcToZonedTime(date, browserTimeZone);
2098
- result = format(result, conversionFormat, this.dateFnsLocale);
2099
- }
2100
- else {
2101
- result = utcToZonedTime(date, browserTimeZone).toString();
2102
- }
2082
+ let d = DateConvert.utcToLocal(date);
2083
+ if (conversionFormat) {
2084
+ result = format(d, conversionFormat, this.dateFnsLocale);
2103
2085
  }
2104
2086
  else {
2105
- if (conversionFormat) {
2106
- result = format(new Date(date), conversionFormat, this.dateFnsLocale);
2107
- }
2108
- else {
2109
- result = new Date(date).toString();
2110
- }
2087
+ result = d.toString();
2111
2088
  }
2112
2089
  }
2113
2090
  catch {