jupyter-ijavascript-utils 1.54.0 → 1.55.0
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/DOCS.md +1 -0
- package/Dockerfile +1 -1
- package/README.md +1 -0
- package/package.json +1 -1
- package/src/chain.js +16 -1
- package/src/date.js +240 -55
- package/src/format.js +2 -0
- package/src/hashMap.js +43 -0
- package/src/ijs.js +85 -0
package/DOCS.md
CHANGED
|
@@ -74,6 +74,7 @@ Give it a try here:
|
|
|
74
74
|
[](https://mybinder.org/v2/gh/paulroth3d/jupyter-ijavascript-utils/main?labpath=example.ipynb)
|
|
75
75
|
|
|
76
76
|
## What's New
|
|
77
|
+
* 1.55 - #76, #77, #74, #78
|
|
77
78
|
* 1.54 - additional Date logic, and formatting. #70 #71 #72
|
|
78
79
|
* 1.53 - additional docs and examples for {@link module:color|color/colour} package.
|
|
79
80
|
* 1.52 - print a date to ISO in local time with {@link module:date.toLocalISO|date.toLocalISO}
|
package/Dockerfile
CHANGED
package/README.md
CHANGED
|
@@ -54,6 +54,7 @@ This is not intended to be the only way to accomplish many of these tasks, and a
|
|
|
54
54
|

|
|
55
55
|
|
|
56
56
|
# What's New
|
|
57
|
+
* 1.55 - #76, #77, #74, #78
|
|
57
58
|
* 1.54 - additional Date logic, and formatting. #70 #71 #72
|
|
58
59
|
* 1.53 - additional docs and examples for color/colour package.
|
|
59
60
|
* 1.52 - print a date to ISO in local time with date.toLocalISO
|
package/package.json
CHANGED
package/src/chain.js
CHANGED
|
@@ -513,6 +513,7 @@ class ChainContainer {
|
|
|
513
513
|
|
|
514
514
|
/**
|
|
515
515
|
* Closes the chain and returns the current value.
|
|
516
|
+
* @param {Function} [functor = null] - optional function (similar to {@link module:chain.chain|chain.chain})
|
|
516
517
|
* @returns {any}
|
|
517
518
|
* @see {@link ChainContainer#chain}
|
|
518
519
|
* @example
|
|
@@ -522,8 +523,22 @@ class ChainContainer {
|
|
|
522
523
|
* .close();
|
|
523
524
|
*
|
|
524
525
|
* // 5
|
|
526
|
+
*
|
|
527
|
+
* //-- or pass an optional function on close
|
|
528
|
+
*
|
|
529
|
+
* doubler = (num) => num + num;
|
|
530
|
+
*
|
|
531
|
+
* utils.chain(3)
|
|
532
|
+
* .chain(doubler)
|
|
533
|
+
* .close(doubler);
|
|
534
|
+
* // 12
|
|
535
|
+
*
|
|
525
536
|
*/
|
|
526
|
-
close() {
|
|
537
|
+
close(functor) {
|
|
538
|
+
if ((typeof functor) === 'function') {
|
|
539
|
+
this.value = this.chain(functor).value;
|
|
540
|
+
}
|
|
541
|
+
|
|
527
542
|
return this.value;
|
|
528
543
|
}
|
|
529
544
|
|
package/src/date.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* * {@link module:date.isValid|date.isValid(date)} - whether the date provided is an invalid date
|
|
7
7
|
* * Parse
|
|
8
8
|
* * {@link module:date.parse|date.parse(String)} - parse a date and throw an exception if it is not a valid date
|
|
9
|
-
* *
|
|
9
|
+
* * Timezones
|
|
10
10
|
* * {@link module:date.toLocalISO|date.toLocalISO} - prints in 8601 format with timezone offset based on a tz entry - like america/chicago
|
|
11
11
|
* * {@link module:date.getTimezoneOffset|date.getTimezoneOffset(String)} - gets the number of milliseconds offset for a given timezone
|
|
12
12
|
* * {@link module:date.correctForTimezone|date.correctForTimezone(Date, String)} - meant to correct a date already off from UTC to the correct time
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
* @exports date
|
|
52
52
|
* @see {@link https://stackoverflow.com/questions/15141762/how-to-initialize-a-javascript-date-to-a-particular-time-zone}
|
|
53
53
|
* @see {@link https://www.youtube.com/watch?v=2rnIHsqABfM&t=750s|epochShifting}
|
|
54
|
-
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/
|
|
54
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTimezones|MDN Timezone Names}
|
|
55
55
|
*/
|
|
56
56
|
module.exports = {};
|
|
57
57
|
const DateUtils = module.exports;
|
|
@@ -181,7 +181,7 @@ module.exports.durationLong = function durationLong(epochDifference) {
|
|
|
181
181
|
};
|
|
182
182
|
|
|
183
183
|
/**
|
|
184
|
-
* @typedef {Object}
|
|
184
|
+
* @typedef {Object} TimezoneEntry
|
|
185
185
|
* @property {String} tz - the name of the timezone
|
|
186
186
|
* @property {Function} formatter - formats a date to that local timezone
|
|
187
187
|
* @property {Number} epoch - the difference in milliseconds from that tz to UTC
|
|
@@ -189,22 +189,22 @@ module.exports.durationLong = function durationLong(epochDifference) {
|
|
|
189
189
|
*/
|
|
190
190
|
|
|
191
191
|
/**
|
|
192
|
-
* Collection of
|
|
192
|
+
* Collection of TimezoneEntries by the tz string
|
|
193
193
|
* @private
|
|
194
|
-
* @type {Map<String,
|
|
194
|
+
* @type {Map<String,TimezoneEntry>}
|
|
195
195
|
*/
|
|
196
|
-
module.exports.
|
|
196
|
+
module.exports.timezoneOffsetMap = new Map();
|
|
197
197
|
|
|
198
198
|
/**
|
|
199
|
-
* Fetches or creates a
|
|
199
|
+
* Fetches or creates a TimezoneEntry
|
|
200
200
|
* @private
|
|
201
|
-
* @param {String}
|
|
202
|
-
* @returns {
|
|
201
|
+
* @param {String} timezoneStr - tz database entry for the timezone
|
|
202
|
+
* @returns {TimezoneEntry}
|
|
203
203
|
*/
|
|
204
|
-
module.exports.getTimezoneEntry = function getTimezoneEntry(
|
|
205
|
-
const cleanTz = String(
|
|
206
|
-
if (DateUtils.
|
|
207
|
-
return DateUtils.
|
|
204
|
+
module.exports.getTimezoneEntry = function getTimezoneEntry(timezoneStr) {
|
|
205
|
+
const cleanTz = String(timezoneStr).toLowerCase();
|
|
206
|
+
if (DateUtils.timezoneOffsetMap.has(cleanTz)) {
|
|
207
|
+
return DateUtils.timezoneOffsetMap.get(cleanTz);
|
|
208
208
|
}
|
|
209
209
|
const d = new Date(Date.UTC(2025, 0, 1, 0, 0, 0));
|
|
210
210
|
|
|
@@ -239,7 +239,7 @@ module.exports.getTimezoneEntry = function getTimezoneEntry(timeZoneStr) {
|
|
|
239
239
|
result[type] = value;
|
|
240
240
|
return result;
|
|
241
241
|
}, {});
|
|
242
|
-
// const impactedDate = new Date(d.toLocaleString('en-US', {
|
|
242
|
+
// const impactedDate = new Date(d.toLocaleString('en-US', { timezone: timezoneStr }));
|
|
243
243
|
const dateStr = `${dm.year}-${DateUtils.padTime(dm.month)}-${DateUtils.padTime(dm.day)}T${
|
|
244
244
|
DateUtils.padTime(dm.hour)}:${DateUtils.padTime(dm.minute)}:${DateUtils.padTime(dm.second)}.${
|
|
245
245
|
DateUtils.padTime(dm.fractionalSecond, 3)}`;
|
|
@@ -260,7 +260,7 @@ module.exports.getTimezoneEntry = function getTimezoneEntry(timeZoneStr) {
|
|
|
260
260
|
|
|
261
261
|
const result = ({ tz: cleanTz, formatter, epoch: diff, offset });
|
|
262
262
|
|
|
263
|
-
DateUtils.
|
|
263
|
+
DateUtils.timezoneOffsetMap.set(cleanTz, result);
|
|
264
264
|
|
|
265
265
|
return result;
|
|
266
266
|
};
|
|
@@ -274,69 +274,180 @@ module.exports.getTimezoneEntry = function getTimezoneEntry(timeZoneStr) {
|
|
|
274
274
|
* See {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones|the list of TZ database time zones}
|
|
275
275
|
* for the full list of options.
|
|
276
276
|
*
|
|
277
|
-
* @param {String}
|
|
278
|
-
* @returns {
|
|
277
|
+
* @param {String} timezoneStr - a timezone string like "America/Toronto"
|
|
278
|
+
* @returns {TimezoneEntry} - the number of milliseconds between UTC and that timezone
|
|
279
279
|
*/
|
|
280
|
-
module.exports.getTimezoneOffset = function getTimezoneOffset(
|
|
281
|
-
return DateUtils.getTimezoneEntry(
|
|
280
|
+
module.exports.getTimezoneOffset = function getTimezoneOffset(timezoneStr) {
|
|
281
|
+
return DateUtils.getTimezoneEntry(timezoneStr).epoch;
|
|
282
282
|
};
|
|
283
283
|
|
|
284
284
|
/**
|
|
285
|
-
*
|
|
285
|
+
* CorrectForTimezone is the opposite of {@link module:date.epochShift|date.epochShift}.
|
|
286
|
+
* (This subtracts the timezone offset to a date, where the other adds the offset)
|
|
286
287
|
*
|
|
287
|
-
* Use this
|
|
288
|
+
* Use this when a date string is read by javascript, BUT the timezone is not sent or passed.
|
|
288
289
|
*
|
|
289
|
-
* For
|
|
290
|
+
* For example, something VERY IMPORTANT happened at '2/1/2025, 2:15:41 PM EST', ISO '2025-02-01T20:15:41.000Z', epoch: 1738440941000.
|
|
291
|
+
*
|
|
292
|
+
* But the dates from the database don't include the timezone.
|
|
293
|
+
* (Note that `Z` is conceptually equivalent of +0000)
|
|
294
|
+
*
|
|
295
|
+
* If I create a date in javaScript WITHOUT the timezone, it assumes my local timezone.
|
|
290
296
|
*
|
|
291
297
|
* ```
|
|
292
|
-
* //
|
|
293
|
-
*
|
|
294
|
-
* dateStr = '2024-12-06 18:00';
|
|
298
|
+
* dTest = new Date('2025-02-01T20:15:41.000'); // -- DID NOT INCLUDE Timezone, so it assumes local timezone
|
|
299
|
+
* ({ epoch: dTest2.getTime(), iso: dTest.toISOString(), local: dTest.toLocaleString() });
|
|
295
300
|
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
301
|
+
* //-- time is INCORRECT, what should be the ISO time, is the local time.
|
|
302
|
+
* // local: '2/1/2025, 8:15:41 PM', iso: '2025-02-02T02:15:41.000Z', epoch: 1738440941000
|
|
303
|
+
* ```
|
|
298
304
|
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
305
|
+
* It assumed that the local time was 8pm instead of that as the ISO / GMT time.
|
|
306
|
+
*
|
|
307
|
+
* To correct this, I just call epoch shift
|
|
301
308
|
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
309
|
+
* ```
|
|
310
|
+
* dTest = new Date('2025-02-01T20:15:41.000'); // -- DID NOT INCLUDE Timezone, so it assumes local timezone
|
|
311
|
+
* dTest2 = utils.date.epochShift(dTest, 'us/central'); //-- correct for my local timezone
|
|
312
|
+
* ({ epoch: dTest2.getTime(), iso: dTest.toISOString(), local: dTest.toLocaleString() });
|
|
313
|
+
*
|
|
314
|
+
* //-- time is CORRECT
|
|
315
|
+
* // local: '2/1/2025, 2:15:41 PM', iso: '2025-02-01T20:15:41.000Z', epoch: 1738440941000
|
|
305
316
|
* ```
|
|
306
317
|
*
|
|
307
318
|
* See {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones|the list of TZ database time zones}
|
|
308
319
|
* for the full list of timezone options.
|
|
309
320
|
*
|
|
310
321
|
* @param {Date} date - the date to be corrected in a new instance
|
|
311
|
-
* @param {String}
|
|
312
|
-
* @returns {Date} -
|
|
322
|
+
* @param {String} localTimezoneStr - tz database name for YOUR current machine's timezone
|
|
323
|
+
* @returns {Date} - new instance of a corrected date back to UTC
|
|
324
|
+
* @see {@link module:date.correctForOtherTimezone|date.correctForOtherTimezone} - if the date given is "local" but for another timezone
|
|
325
|
+
* @see {@link module:date.toLocalISO|date.toLocalISO} - if you want to print a date to another timezone
|
|
313
326
|
*/
|
|
314
|
-
module.exports.correctForTimezone = function correctForTimezone(date,
|
|
315
|
-
const { epoch } = DateUtils.getTimezoneEntry(
|
|
316
|
-
return new Date(date.getTime()
|
|
327
|
+
module.exports.correctForTimezone = function correctForTimezone(date, localTimezoneStr) {
|
|
328
|
+
const { epoch } = DateUtils.getTimezoneEntry(localTimezoneStr);
|
|
329
|
+
return new Date(date.getTime() - epoch);
|
|
317
330
|
};
|
|
318
331
|
|
|
319
332
|
/**
|
|
333
|
+
* This helps you correct a "local date" from another timezone.
|
|
334
|
+
*
|
|
335
|
+
* For example, if you got '2:15 PM' from a machine that is in eastern.
|
|
336
|
+
*
|
|
337
|
+
* Combination of {@link module:date.correctForTimezone|date.correctForTimezone}
|
|
338
|
+
* and {@link module:date.epochShift|date.epochShift}
|
|
339
|
+
*
|
|
340
|
+
* For example, say you got a timezone string like this: `2024-12-27 13:30:00`
|
|
341
|
+
*
|
|
342
|
+
* You know the timezone of the source is in `us/eastern`, but you are in `us/central`.
|
|
343
|
+
*
|
|
344
|
+
* If you just use `Date.parse(dateString), it assumes `1:30 Central` - not `1:30 Eastern`
|
|
345
|
+
*
|
|
346
|
+
* We can correct it like this:
|
|
347
|
+
*
|
|
348
|
+
* ```
|
|
349
|
+
* dateStr = '2024-12-27 13:30:00';
|
|
350
|
+
* d = new Date(Date.parse(dateStr));
|
|
351
|
+
*
|
|
352
|
+
* //-- the source was from 'us/eastern' timezone (-0500)
|
|
353
|
+
* sourceTimezone = 'us/eastern';
|
|
354
|
+
*
|
|
355
|
+
* //-- we are currently in 'us/central' timezone (-0600)
|
|
356
|
+
* //-- this matters because of the Date.parse() done before
|
|
357
|
+
* localTimezone = 'us/central'; // (change if yours is different)
|
|
358
|
+
*
|
|
359
|
+
* utils.date.correctForOtherTimezone( d, sourceTimezone, localTimezone);
|
|
360
|
+
*
|
|
361
|
+
* //-- correctly converted it to the correct local time
|
|
362
|
+
* // 2024-12-28T18:30:00.000Z
|
|
363
|
+
* ```
|
|
364
|
+
*
|
|
365
|
+
* @param {Date} date - the date to be corrected in a new instance
|
|
366
|
+
* @param {string} sourceTimezone - the timezone of the source information
|
|
367
|
+
* @param {string} localTimezone - the timezone of this local machine
|
|
368
|
+
* @returns {Date} - new date that is corrected to UTC
|
|
369
|
+
* @see {@link module:date.toLocalISO|date.toLocalISO} - if you want to print a date to another timezone
|
|
370
|
+
*/
|
|
371
|
+
module.exports.correctForOtherTimezone = function correctForTimezones(date, sourceTimezone, localTimezone) {
|
|
372
|
+
return DateUtils.correctForTimezone(
|
|
373
|
+
DateUtils.epochShift(date, sourceTimezone),
|
|
374
|
+
localTimezone
|
|
375
|
+
);
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* EpochShift is the opposite of {@link module:date.correctForTimezone|date.correctForTimezone}.
|
|
380
|
+
* (This adds the timezone offset, where the other subtracts the offset)
|
|
381
|
+
*
|
|
382
|
+
* Use this if you somehow have a date that needs to be shifted by the timezone offset.
|
|
383
|
+
*
|
|
384
|
+
* This is rarely useful in itself, but in combination with the {@link module:date.correctForTimezone|date.correctForTimezone}
|
|
385
|
+
* you can use this to correct for "local dates" but are in another timezone than you are in.
|
|
386
|
+
*
|
|
387
|
+
* (For example, you got a local date for 2:15 PM EST, but your current computer is in CST)
|
|
388
|
+
*
|
|
389
|
+
* JavaScript dates only have three ways of importing dates:
|
|
390
|
+
*
|
|
391
|
+
* * Parse the date assuming local timezone
|
|
392
|
+
* * Parse the date using [ISO 8601 formats](https://www.iso.org/iso-8601-date-and-time-format.html)
|
|
393
|
+
* * This option DOES provide an option for providing a timezone offset (ex: `-0500`)
|
|
394
|
+
*
|
|
395
|
+
* Since this is the opposite of {@link module:date.correctForTimezone|date.correctForTimezone}, this can be useful.
|
|
396
|
+
*
|
|
397
|
+
* But most likely, you'd like to use either:
|
|
398
|
+
*
|
|
399
|
+
* * {@link module:date.correctForTimezone|date.correctForTimezone} or
|
|
400
|
+
* * {@link module:date.correctForTimezones|date.correctForTimezones}.
|
|
401
|
+
*
|
|
402
|
+
* ---
|
|
403
|
+
*
|
|
320
404
|
* Epoch shift a date, so the utcDate is no longer correct,
|
|
321
405
|
* but many other functions behave closer to expected.
|
|
322
406
|
*
|
|
407
|
+
* Once you epoch shift the date, then time stored in the date is incorrect (because it always points to GMT)
|
|
408
|
+
*
|
|
409
|
+
* For example, using `.toIsoString()` or anything with Intl.DateTimeFormat etc - will all give you incorrect results.
|
|
410
|
+
*
|
|
323
411
|
* See {@link https://stackoverflow.com/a/15171030|here why this might not be what you want}
|
|
324
412
|
*
|
|
413
|
+
* --
|
|
414
|
+
*
|
|
415
|
+
* Sometimes though, some libraries use the "getMonth()", "getDate()" of the date, and do not support using timezones.
|
|
416
|
+
*
|
|
417
|
+
* That is when this shines.
|
|
418
|
+
*
|
|
419
|
+
* ```
|
|
420
|
+
* timeStamp = 1738437341000;
|
|
421
|
+
* d = new Date(timeStamp);
|
|
422
|
+
* d.toIsoString(); // 2025-02-01T19:15:41.000Z
|
|
423
|
+
* `current time is: ${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}` // 'current time is: 2025-2-1'
|
|
424
|
+
*
|
|
425
|
+
*
|
|
426
|
+
* ```
|
|
427
|
+
*
|
|
325
428
|
* @param {Date} date - date to shift
|
|
326
|
-
* @param {String}
|
|
429
|
+
* @param {String} timezoneStr - the tz database name of the timezone
|
|
327
430
|
* @returns {Date}
|
|
431
|
+
* @see {@link module:date.toEpochShiftedISO|date.toEpochShiftedISO} - this will print the
|
|
432
|
+
* "local time" of an epoch shifted date.
|
|
328
433
|
* @see {@link module:date.toLocalISO|date.toLocalISO} - consider as an alternative.
|
|
329
434
|
* This prints the correct time, without updating the date object.
|
|
435
|
+
* @see {@link module:date.correctForTimezone|date.correctForTimezone} - once shifted,
|
|
436
|
+
* this allows you to shift a date back to GMT time.
|
|
330
437
|
*/
|
|
331
|
-
module.exports.epochShift = function epochShift(date,
|
|
332
|
-
const { epoch } = DateUtils.getTimezoneEntry(
|
|
333
|
-
return new Date(date.getTime()
|
|
438
|
+
module.exports.epochShift = function epochShift(date, timezoneStr) {
|
|
439
|
+
const { epoch } = DateUtils.getTimezoneEntry(timezoneStr);
|
|
440
|
+
return new Date(date.getTime() + epoch);
|
|
334
441
|
};
|
|
335
442
|
|
|
336
443
|
/**
|
|
337
|
-
* Prints a date in 8601 format to a timezone (with +H:MM offset)
|
|
444
|
+
* Prints a date in 8601 format to a timezone (with +H:MM offset) using
|
|
445
|
+
* [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat).
|
|
338
446
|
*
|
|
339
|
-
*
|
|
447
|
+
* The date accepted here is assumed to already have the internal clock set to GMT.
|
|
448
|
+
*
|
|
449
|
+
* If you do epochShift, then use {@link module:date.toEpochShiftedISO|date.toEpochShiftedISO}
|
|
450
|
+
* and pass the timezone the timezone the date is epoch shifted to.
|
|
340
451
|
*
|
|
341
452
|
* ```
|
|
342
453
|
* d = Date.parse('2024-12-27 13:30:00');
|
|
@@ -346,14 +457,55 @@ module.exports.epochShift = function epochShift(date, timeZoneStr) {
|
|
|
346
457
|
* ```
|
|
347
458
|
*
|
|
348
459
|
* @param {Date} date - date to print
|
|
349
|
-
* @param {String}
|
|
460
|
+
* @param {String} timezoneStr - the tz database name of the timezone
|
|
350
461
|
* @returns {String} - ISO format with timezone offset
|
|
351
462
|
*/
|
|
352
|
-
module.exports.toLocalISO = function toLocalISO(date,
|
|
353
|
-
const { formatter, offset } = DateUtils.getTimezoneEntry(
|
|
463
|
+
module.exports.toLocalISO = function toLocalISO(date, timezoneStr) {
|
|
464
|
+
const { formatter, offset } = DateUtils.getTimezoneEntry(timezoneStr);
|
|
354
465
|
return `${formatter(date)}${offset}`;
|
|
355
466
|
};
|
|
356
467
|
|
|
468
|
+
module.exports.toIsoStringNoTimezone = function toIsoStringNoTimezone(date) {
|
|
469
|
+
return `${
|
|
470
|
+
date.getFullYear()
|
|
471
|
+
}-${
|
|
472
|
+
String(date.getMonth() + 1).padStart(2, '0')
|
|
473
|
+
}-${
|
|
474
|
+
String(date.getDate()).padStart(2, '0')
|
|
475
|
+
}T${
|
|
476
|
+
String(date.getHours()).padStart(2, '0')
|
|
477
|
+
}:${
|
|
478
|
+
String(date.getMinutes()).padStart(2, '0')
|
|
479
|
+
}:${
|
|
480
|
+
String(date.getSeconds()).padStart(2, '0')
|
|
481
|
+
}.${
|
|
482
|
+
String(date.getMilliseconds()).padStart(3, '0')
|
|
483
|
+
}`;
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Print a date that has been epoch shifted.
|
|
488
|
+
*
|
|
489
|
+
* Dates in JavaScript are always stored in GMT, although you can format it to different times with
|
|
490
|
+
* [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat).
|
|
491
|
+
*
|
|
492
|
+
* Once you epoch shift the date, then time stored in the date is incorrect (because it always points to GMT)
|
|
493
|
+
*
|
|
494
|
+
* For example, using `.toIsoString()` or anything with Intl.DateTimeFormat etc - will all give you incorrect results.
|
|
495
|
+
*
|
|
496
|
+
* If you want an ISO format for an epoch shifted date, you'll need something like this.
|
|
497
|
+
*
|
|
498
|
+
* @param {Date} date - Date to Print
|
|
499
|
+
* @param {String} timezoneStr - the tz database name of the timezone the date is shifted to
|
|
500
|
+
* @returns {String} date in the format of `YYYY-MM-DDTHH:mm:SS.MMMM[+-]TZ`
|
|
501
|
+
* @see {@link module:date.correctForTimezone|date.correctForTimezone} - to shift the date back to GMT
|
|
502
|
+
* @see {@link module:date.toLocalISO|date.toLocalISO} - if the date is not epoch shifted as this uses Intl.DateTimeFormat
|
|
503
|
+
*/
|
|
504
|
+
module.exports.toEpochShiftedISO = function toEpochShiftedISO(date, timezoneStr) {
|
|
505
|
+
const { offset } = DateUtils.getTimezoneEntry(timezoneStr);
|
|
506
|
+
return `${DateUtils.toIsoStringNoTimezone(date)}${offset}`;
|
|
507
|
+
};
|
|
508
|
+
|
|
357
509
|
/**
|
|
358
510
|
* Clones a date.
|
|
359
511
|
*
|
|
@@ -421,7 +573,7 @@ module.exports.overwrite = function overwrite(dateToUpdate, newDateEpoch) {
|
|
|
421
573
|
* @param {Number} [options.minutes=0] - number of minutes to add
|
|
422
574
|
* @param {Number} [options.hours=0] - number of minutes to add
|
|
423
575
|
* @param {Number} [options.seconds=0] - number of seconds to add
|
|
424
|
-
* @returns {Date} -
|
|
576
|
+
* @returns {Date} - Date with the interval added in
|
|
425
577
|
*/
|
|
426
578
|
module.exports.add = function add(dateValue, options = null) {
|
|
427
579
|
if (!options) return dateValue;
|
|
@@ -503,8 +655,9 @@ module.exports.startOfDay = function endOfDay(dateValue) {
|
|
|
503
655
|
* @param {Number} [options.years=0] - increments the calendar year (as opposed to adding 365.25 days)
|
|
504
656
|
* @param {Number} [options.months=0] - increments the calendar month (as opposed to adding in 30 days)
|
|
505
657
|
* @returns {Date[]} - collection of dates (count long)
|
|
506
|
-
* @see {@link module:
|
|
507
|
-
* @see {@link module:date.generateDateSequence} - finish at an endingDate instead of # of iterations
|
|
658
|
+
* @see {@link module:date.add|utils.date.add}
|
|
659
|
+
* @see {@link module:date.generateDateSequence|date.generateDateSequence} - finish at an endingDate instead of # of iterations
|
|
660
|
+
* @see {@link module:date~DateRange.fromList|DateRange.fromList} - to create Date Ranges from these dates.
|
|
508
661
|
*/
|
|
509
662
|
module.exports.arrange = function arrange(startDate, count, options) {
|
|
510
663
|
if (!DateUtils.isValid(startDate)) {
|
|
@@ -553,10 +706,11 @@ module.exports.arrange = function arrange(startDate, count, options) {
|
|
|
553
706
|
* @param {Number} [options.years=0] - increments the calendar year (as opposed to adding 365.25 days)
|
|
554
707
|
* @param {Number} [options.months=0] - increments the calendar month (as opposed to adding in 30 days)
|
|
555
708
|
* @returns {Date[]} - sequence of dates from startDate to endDate
|
|
556
|
-
* @see {@link module:
|
|
557
|
-
* @see {@link module:date.arrange} - run a set of iterations instead of stopping at endDate
|
|
709
|
+
* @see {@link module:date.add|utils.date.add}
|
|
710
|
+
* @see {@link module:date.arrange|date.arrange} - run a set of iterations instead of stopping at endDate
|
|
711
|
+
* @see {@link module:date~DateRange.fromList|DateRange.fromList} - to create Date Ranges from these dates.
|
|
558
712
|
*/
|
|
559
|
-
module.exports.generateDateSequence = function
|
|
713
|
+
module.exports.generateDateSequence = function generateDateSequence(startDate, endDate, options) {
|
|
560
714
|
const results = [];
|
|
561
715
|
|
|
562
716
|
if (!DateUtils.isValid(startDate)) {
|
|
@@ -581,7 +735,28 @@ module.exports.generateDateSequence = function generateDateSequencde(startDate,
|
|
|
581
735
|
};
|
|
582
736
|
|
|
583
737
|
/**
|
|
584
|
-
* Represents a Range between two
|
|
738
|
+
* Represents a Range between two timestamps.
|
|
739
|
+
*
|
|
740
|
+
* * Creating Date Range
|
|
741
|
+
* * {@link module:date~DateRange.fromList|fromList} - given a list of dates, make range bins for those dates.
|
|
742
|
+
* * {@link module:date~DateRange#reinitialize|reinitialize} - initialize the dateRange in-place with new start/end dates
|
|
743
|
+
* * {@link module:date~DateRange#shiftStart|shiftStart} - shifts the start of the range by hours,minutes,years, etc.
|
|
744
|
+
* * {@link module:date~DateRange#shiftEnd|shiftEnd} - shifts the start of the range by hours,minutes,years, etc.
|
|
745
|
+
*
|
|
746
|
+
* * Understanding the Date Range
|
|
747
|
+
* * {@link module:date~DateRange#contains|contains} - if a date is within this range.
|
|
748
|
+
* * {@link module:date~DateRange#startDate|startDate} - the starting date of the range
|
|
749
|
+
* * {@link module:date~DateRange#endDate|endingDate} - the ending date of the range
|
|
750
|
+
* * {@link module:date~DateRange.startAndEndOfDay|startAndEndOfDay} - Creates a DateRange covering the start and end of a day
|
|
751
|
+
* * {@link module:date~DateRange#overlaps|overlaps} - whether this DateRange overlaps another DateRange
|
|
752
|
+
* * {@link module:date~DateRange#isValid|isValid} - Whether the start and end times of this range are both valid dates
|
|
753
|
+
* * Durations
|
|
754
|
+
* * {@link module:date~DateRange#duration|duration} - Epoch duration (milliseconds) between the start and end timestamps
|
|
755
|
+
* * {@link module:date~DateRange#durationString|durationString} - creates a long duration description
|
|
756
|
+
* * {@link module:date~DateRange#durationISO|durationISO} - returns the duration as a string formatted '0:01:00:00.0000'
|
|
757
|
+
* * String Representation
|
|
758
|
+
* * {@link module:date~DateRange#toString|toString} - String conversion of the DateRange
|
|
759
|
+
* * {@link module:date~DateRange#toLocaleString|toLocaleString} - Creates a locale string describing the DateRange
|
|
585
760
|
*/
|
|
586
761
|
class DateRange {
|
|
587
762
|
/**
|
|
@@ -619,12 +794,18 @@ class DateRange {
|
|
|
619
794
|
* // {start: 2025-03-01TT00:00:00, end: 2025-04-01TT00:00:00}]
|
|
620
795
|
* ```
|
|
621
796
|
*
|
|
797
|
+
* (Note: you can also use {@link module:date.arrange|date.arrange} or
|
|
798
|
+
* {@link module:date.generateDateSequence|date.generateDateSequence}
|
|
799
|
+
* to come up with the list of those dates)
|
|
800
|
+
*
|
|
622
801
|
* (If gaps are desired - ex: April to May and next one June to July,
|
|
623
802
|
* the simplest is to remove the dates from the resulting list.)
|
|
624
803
|
*
|
|
625
804
|
* @param {Date[]} dateList - list of dates
|
|
626
805
|
* @returns {DateRange[]} - list of dateList.length-1 dateRanges,
|
|
627
806
|
* where the end of the firstRange is the start of the next.
|
|
807
|
+
* @see {@link module:date.arrange|date.arrange} - to create dates by adding a value multiple times
|
|
808
|
+
* @see {@link module:date.generateDateSequence|date.generateDateSequence} - to create dates between a start and an end date
|
|
628
809
|
*/
|
|
629
810
|
static fromList(dateSequence) {
|
|
630
811
|
if (dateSequence.length < 2) return [];
|
|
@@ -666,6 +847,10 @@ class DateRange {
|
|
|
666
847
|
*
|
|
667
848
|
* This is very useful for determining overlapping dates.
|
|
668
849
|
*
|
|
850
|
+
* (Alternatively, you can define a list of dates, and use
|
|
851
|
+
* {@link module:date~DateRange.fromList|DateRange.fromList}
|
|
852
|
+
* to create the bins from those dates)
|
|
853
|
+
*
|
|
669
854
|
* @param {Date} targetDate - date to use to find the start and end UTC for
|
|
670
855
|
* @returns {DateRange}
|
|
671
856
|
*/
|
|
@@ -756,7 +941,7 @@ class DateRange {
|
|
|
756
941
|
* @param {Number} [options.years=0] - increments the calendar year (as opposed to adding 365.25 days)
|
|
757
942
|
* @param {Number} [options.months=0] - increments the calendar month (as opposed to adding in 30 days)
|
|
758
943
|
* @param {*} inPlace
|
|
759
|
-
* @returns
|
|
944
|
+
* @returns {DateRange} - this DateRange if (inPlace=true), a new instance if (inPlace=false)
|
|
760
945
|
*/
|
|
761
946
|
shiftStart(options, inPlace = false) {
|
|
762
947
|
if (inPlace) {
|
|
@@ -798,7 +983,7 @@ class DateRange {
|
|
|
798
983
|
* @param {Number} [options.years=0] - increments the calendar year (as opposed to adding 365.25 days)
|
|
799
984
|
* @param {Number} [options.months=0] - increments the calendar month (as opposed to adding in 30 days)
|
|
800
985
|
* @param {*} inPlace
|
|
801
|
-
* @returns
|
|
986
|
+
* @returns {DateRange} - this DateRange if (inPlace=true), a new instance if (inPlace=false)
|
|
802
987
|
*/
|
|
803
988
|
shiftEnd(options, inPlace = false) {
|
|
804
989
|
if (inPlace) {
|
package/src/format.js
CHANGED
|
@@ -43,6 +43,8 @@
|
|
|
43
43
|
* * {@link module:format.isEmptyValue|format.isEmptyValue} - determine if a value is not 'empty'
|
|
44
44
|
* * Extracting values
|
|
45
45
|
* * {@link module:format.extractWords|format.extractWords} - to extract the words from a string
|
|
46
|
+
* * Making Printing Easier
|
|
47
|
+
* * {@link module:format.clearOutput|format.clearOutput} - has the output cleared. Helpful for setting variables, or importing libraries.
|
|
46
48
|
*
|
|
47
49
|
* @module format
|
|
48
50
|
* @exports format
|
package/src/hashMap.js
CHANGED
|
@@ -5,6 +5,7 @@ const FormatUtils = require('./format');
|
|
|
5
5
|
*
|
|
6
6
|
* * Modifying
|
|
7
7
|
* * {@link module:hashMap.add|hashMap.add(map, key, value):Map} - Add a value to a map and return the Map
|
|
8
|
+
* * {@link module:hashMap.update|hashMap.update(map, key, function)} - use a function to get/set a value on a map
|
|
8
9
|
* * {@link module:hashMap.union|hashMap.union(targetMap, additionalMap, canOverwrite)} - merges two maps and ignores or overwrites with conflicts
|
|
9
10
|
* * Cloning
|
|
10
11
|
* * {@link module:hashMap.clone|hashMap.clone(map):Map} - Clones a given Map
|
|
@@ -50,6 +51,48 @@ module.exports.add = function add(map, key, value) {
|
|
|
50
51
|
return map;
|
|
51
52
|
};
|
|
52
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Use this for times where you want to update a value
|
|
56
|
+
*
|
|
57
|
+
* ```
|
|
58
|
+
* key = 'somethingToIncrement';
|
|
59
|
+
* defaultValue = null;
|
|
60
|
+
*
|
|
61
|
+
* const initialMap = new Map([
|
|
62
|
+
* [key, defaultValue]
|
|
63
|
+
* ]);
|
|
64
|
+
* // Map([[ 'somethingToIncrement', null ]]);
|
|
65
|
+
*
|
|
66
|
+
* const functor = (value) => { //, key, map) => {
|
|
67
|
+
* if (!value) return 1;
|
|
68
|
+
* return value + 1;
|
|
69
|
+
* };
|
|
70
|
+
*
|
|
71
|
+
* HashMapUtil.getSet(initialMap, key, functor);
|
|
72
|
+
* HashMapUtil.getSet(initialMap, key, functor);
|
|
73
|
+
* HashMapUtil.getSet(initialMap, key, functor);
|
|
74
|
+
* HashMapUtil.getSet(initialMap, key, functor);
|
|
75
|
+
* HashMapUtil.getSet(initialMap, key, functor);
|
|
76
|
+
*
|
|
77
|
+
* initialMap.get(key); // 5
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @param {Map} map - map to get and set values from
|
|
81
|
+
* @param {any} key - they key to GET and SET the value (unless setKey is provided)
|
|
82
|
+
* @param {Function} functor - the function called with the arguments below - returning the value to set
|
|
83
|
+
* @param {any} functor.value - the first argument is the current value
|
|
84
|
+
* @param {any} functor.key - the second argument is the key passed
|
|
85
|
+
* @param {any} functor.map - the third argument is the map being acted upon
|
|
86
|
+
* @param {any} [setKey = null] - optional separate key to use to set the updated value
|
|
87
|
+
* @returns {Map}
|
|
88
|
+
*/
|
|
89
|
+
module.exports.getSet = function getSet(map, key, functor, setKey = null) {
|
|
90
|
+
const cleanSetKey = setKey || key;
|
|
91
|
+
map.set(cleanSetKey, functor(map.get(key), key, map));
|
|
92
|
+
return map;
|
|
93
|
+
};
|
|
94
|
+
module.exports.update = module.exports.getSet;
|
|
95
|
+
|
|
53
96
|
/**
|
|
54
97
|
* Clones a Map
|
|
55
98
|
* @param {Map} target - Map to clone
|
package/src/ijs.js
CHANGED
|
@@ -23,6 +23,10 @@ require('./_types/global');
|
|
|
23
23
|
* * Rendering
|
|
24
24
|
* * {@link module:ijs.markdown|ijs.markdown} - Render output as markdown
|
|
25
25
|
* * {@link module:ijs.htmlScript|ijs.htmlScript} - Leverage external libraries like D3, Leaflet, etc.
|
|
26
|
+
* * Printing
|
|
27
|
+
* * {@link module:ijs.noOutputNeeded|ijs.noOutputNeeded} - clears the output to declutter results (like importing libraries, or functions)
|
|
28
|
+
* * {@link module:ijs.initializePageBreaks|ijs.initializePageBreaks} - call at least once to allow pageBreaks when rendering PDFs
|
|
29
|
+
* * {@link module:ijs.printPageBreak|ijs.printPageBreak} - call to print a page break when rendering PDFs
|
|
26
30
|
*
|
|
27
31
|
* For example:
|
|
28
32
|
*
|
|
@@ -577,3 +581,84 @@ module.exports.htmlScript = function htmlScripts(
|
|
|
577
581
|
|
|
578
582
|
return results;
|
|
579
583
|
};
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Clears the output.
|
|
587
|
+
*
|
|
588
|
+
* (This is useful to put after importing libraries,
|
|
589
|
+
* or defining a list of functions)
|
|
590
|
+
*/
|
|
591
|
+
module.exports.noOutputNeeded = function clearOutput(outputText = '') {
|
|
592
|
+
//-- you must be in iJavaScript container to rendeer
|
|
593
|
+
const context = IJSUtils.detectContext();
|
|
594
|
+
|
|
595
|
+
if (!context) {
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
context.$$.text(outputText);
|
|
600
|
+
};
|
|
601
|
+
module.exports.clearOutput = module.exports.noOutputNeeded;
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Required to be called first - in order to write page-breaks in the html results.
|
|
605
|
+
*
|
|
606
|
+
* (For Example:)
|
|
607
|
+
*
|
|
608
|
+
* Assume you have the following cells:
|
|
609
|
+
*
|
|
610
|
+
* ```
|
|
611
|
+
* * Some Text
|
|
612
|
+
* * utils.ijs.initializePageBreaks()
|
|
613
|
+
* * some other text
|
|
614
|
+
* * utils.ijs.printPageBreak();
|
|
615
|
+
* * end of document
|
|
616
|
+
* ```
|
|
617
|
+
*
|
|
618
|
+
* When you print to HTML and then render to PDF, you'll see the following:
|
|
619
|
+
*
|
|
620
|
+
* ```
|
|
621
|
+
* * Some Text
|
|
622
|
+
* * utils.ijs.initializePageBreaks()
|
|
623
|
+
*
|
|
624
|
+
* //-- page break
|
|
625
|
+
*
|
|
626
|
+
* * some other text
|
|
627
|
+
* * utils.ijs.printPageBreak();
|
|
628
|
+
*
|
|
629
|
+
* //-- page break
|
|
630
|
+
*
|
|
631
|
+
* * end of document
|
|
632
|
+
* ```
|
|
633
|
+
*/
|
|
634
|
+
module.exports.initializePageBreaks = function initializePageBreaks() {
|
|
635
|
+
//-- you must be in iJavaScript container to rendeer
|
|
636
|
+
const context = IJSUtils.detectContext();
|
|
637
|
+
|
|
638
|
+
if (!context) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
context.$$.html(`<style>
|
|
643
|
+
@media print {
|
|
644
|
+
.pagebreak { page-break-before: always; } /* page-break-after works, as well */
|
|
645
|
+
}
|
|
646
|
+
</style>
|
|
647
|
+
<div class="pagebreak"></div>
|
|
648
|
+
`);
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* After the {@see module:ijs.initializePageBreaks|utils.ijs.initializePageBreaks} is called,
|
|
653
|
+
* this will create another page break.
|
|
654
|
+
*/
|
|
655
|
+
module.exports.printPageBreak = function printPageBreak() {
|
|
656
|
+
//-- you must be in iJavaScript container to rendeer
|
|
657
|
+
const context = IJSUtils.detectContext();
|
|
658
|
+
|
|
659
|
+
if (!context) {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
context.$$.html('<div class="pagebreak"></div>');
|
|
664
|
+
};
|