nhb-toolbox 4.20.70 → 4.20.80

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,14 @@ All notable changes to the package will be documented here.
6
6
 
7
7
  ---
8
8
 
9
+ ## [4.20.80] - 2025-10-07
10
+
11
+ ### 🕧 Updates in Chronos
12
+
13
+ - **Added** _overload signatures_ for `isWeekend`, `isWorkDay` and `isBusinessHour` methods from `businessPlugin`.
14
+ - **Fixed** issues with `isBusinessHour`: previously skipped _business start and end hours_ in some cases.
15
+ - **Added** new _utility type_ `RangeTuple` to create _ranged tuple_.
16
+
9
17
  ## [4.20.69-70] - 2025-10-07
10
18
 
11
19
  ### 🕧 Updates in Chronos
@@ -204,19 +204,20 @@ class Chronos {
204
204
  }
205
205
  #normalizeDuration(result, absolute, isFuture) {
206
206
  const entries = Object.entries(result);
207
+ const updated = {};
207
208
  if (!absolute && !isFuture) {
208
209
  for (const [key, value] of entries) {
209
210
  if (value !== 0) {
210
- result[key] = value * -1;
211
+ updated[key] = value * -1;
211
212
  }
212
213
  }
213
214
  }
214
215
  else if (absolute) {
215
216
  for (const [key, value] of entries) {
216
- result[key] = Math.abs(value);
217
+ updated[key] = Math.abs(value);
217
218
  }
218
219
  }
219
- return result;
220
+ return updated;
220
221
  }
221
222
  get year() {
222
223
  return this.#date.getFullYear();
@@ -2,36 +2,44 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.businessPlugin = void 0;
4
4
  const non_primitives_1 = require("../../guards/non-primitives");
5
+ const primitives_1 = require("../../guards/primitives");
5
6
  const constants_1 = require("../constants");
6
7
  const businessPlugin = (ChronosClass) => {
7
8
  const internalDate = ChronosClass[constants_1.INTERNALS].internalDate;
8
- ChronosClass.prototype.isWeekend = function (weekStartsOn = 0, weekendLength = 2, weekendDays) {
9
+ ChronosClass.prototype.isWeekend = function (determiner = 0, weekendLength = 2) {
9
10
  const day = internalDate(this).getDay();
10
- if ((0, non_primitives_1.isValidArray)(weekendDays)) {
11
- return weekendDays.includes(day);
11
+ if ((0, non_primitives_1.isValidArray)(determiner)) {
12
+ return determiner.includes(day);
12
13
  }
13
- const lastDayOfWeek = (weekStartsOn + 6) % 7;
14
+ const lastDayOfWeek = (determiner + 6) % 7;
14
15
  const computedWeekendDays = Array.from({ length: weekendLength }, (_, i) => (lastDayOfWeek - i + 7) % 7);
15
16
  return computedWeekendDays.includes(day);
16
17
  };
17
- ChronosClass.prototype.isWorkday = function (weekStartsOn = 0, weekendLength = 2, weekendDays) {
18
- return !this.isWeekend(weekStartsOn, weekendLength, weekendDays);
18
+ ChronosClass.prototype.isWorkday = function (determiner = 0, weekendLength = 2) {
19
+ if ((0, non_primitives_1.isValidArray)(determiner)) {
20
+ return !this.isWeekend(determiner);
21
+ }
22
+ return !this.isWeekend(determiner, weekendLength);
19
23
  };
20
24
  ChronosClass.prototype.isBusinessHour = function (options) {
21
- const { businessStartHour = 9, businessEndHour = 17, weekStartsOn = 0, weekendLength = 2, weekendDays, } = options ?? {};
22
- if (this.isWeekend(weekStartsOn, weekendLength, weekendDays)) {
23
- return false;
24
- }
25
- const hour = internalDate(this).getHours();
26
- if (businessStartHour === businessEndHour) {
27
- return false;
28
- }
29
- if (businessStartHour < businessEndHour) {
30
- return hour >= businessStartHour && hour < businessEndHour;
31
- }
32
- else {
33
- return hour >= businessStartHour || hour < businessEndHour;
25
+ const _isBusinessHour = () => {
26
+ const { businessStartHour = 9, businessEndHour = 17 } = options ?? {};
27
+ if (businessStartHour === businessEndHour) {
28
+ return false;
29
+ }
30
+ const hour = internalDate(this).getHours();
31
+ if (businessStartHour < businessEndHour) {
32
+ return hour >= businessStartHour && hour < businessEndHour;
33
+ }
34
+ else {
35
+ return hour >= businessStartHour || hour < businessEndHour;
36
+ }
37
+ };
38
+ if (options && 'weekendDays' in options && !(0, primitives_1.isUndefined)(options?.weekendDays)) {
39
+ return this.isWorkday(options?.weekendDays) && _isBusinessHour();
34
40
  }
41
+ const { weekStartsOn = 0, weekendLength = 2 } = (options ?? {});
42
+ return this.isWorkday(weekStartsOn, weekendLength) && _isBusinessHour();
35
43
  };
36
44
  ChronosClass.prototype.toFiscalQuarter = function (startMonth = 7) {
37
45
  const month = internalDate(this).getMonth() + 1;
@@ -1,15 +1,14 @@
1
1
  import type { Enumerate, NumberRange } from '../../number/types';
2
- import type { TupleOf } from '../../utils/types';
3
- import type { BusinessHourOptions, Quarter } from '../types';
2
+ import type { RangeTuple } from '../../utils/types';
3
+ import type { AcademicYear, BusinessOptionsBasic, BusinessOptionsWeekends, Quarter } from '../types';
4
4
  type MainChronos = typeof import('../Chronos').Chronos;
5
5
  declare module '../Chronos' {
6
6
  interface Chronos {
7
7
  /**
8
- * @instance Checks if the current date falls on a weekend.
8
+ * @instance Checks if the current date falls on a weekend using week start day and weekend length.
9
9
  *
10
10
  * @param weekStartsOn Optional. The day index (0–6) that the week starts on. Default is `0` (Sunday).
11
11
  * @param weekendLength Optional. The number of consecutive days at the end of the week considered as weekend. Must be between 1 and 4. Default is `2`.
12
- * @param weekendDays Optional. A tuple of custom weekend day indices (0–6). Its length must match `weekendLength`. If provided, this overrides `weekStartsOn` + `weekendLength` calculation.
13
12
  * @returns `true` if the current date is a weekend day according to the provided parameters; otherwise `false`.
14
13
  *
15
14
  * @description
@@ -19,7 +18,6 @@ declare module '../Chronos' {
19
18
  * - By default (`weekStartsOn = 0`, `weekendLength = 2`), Saturday (6) and Friday (5) are considered weekend.
20
19
  * - `weekStartsOn` sets the start of the week for calculating weekend days.
21
20
  * - `weekendLength` sets how many days at the end of the week are treated as weekend.
22
- * - `weekendDays`, if provided, is used directly as the weekend days instead of calculating from `weekStartsOn` + `weekendLength`.
23
21
  *
24
22
  * @example
25
23
  * // Default: Saturday & Friday are weekend
@@ -30,17 +28,30 @@ declare module '../Chronos' {
30
28
  *
31
29
  * // Custom 3-day weekend (Friday, Saturday, Sunday)
32
30
  * new Chronos().isWeekend(1, 3);
31
+ */
32
+ isWeekend(weekStartsOn?: Enumerate<7>, weekendLength?: NumberRange<1, 4>): boolean;
33
+ /**
34
+ * @instance Checks if the current date falls on a weekend using indices of weekend days.
33
35
  *
36
+ * @param weekendDays Optional. A tuple of custom weekend day indices (0–6). Can pass only 1-4 elements.
37
+ * @returns `true` if the current date is a weekend day according to the provided `weekendDays`; otherwise `false`.
38
+ *
39
+ * @description
40
+ * Determines whether the current date is considered part of the weekend.
41
+ *
42
+ * **Behavior:**
43
+ * - `weekendDays` is used directly as the weekend days instead of calculating from `weekStartsOn` + `weekendLength`.
44
+ *
45
+ * @example
34
46
  * // Fully custom weekend days (Sunday, Friday, Saturday)
35
- * new Chronos().isWeekend(0, 3, [0, 5, 6]);
47
+ * new Chronos().isWeekend([0, 5, 6]);
36
48
  */
37
- isWeekend<Length extends NumberRange<1, 4>>(weekStartsOn?: Enumerate<7>, weekendLength?: Length, weekendDays?: TupleOf<Enumerate<7>, Length>): boolean;
49
+ isWeekend(weekendDays: RangeTuple<Enumerate<7>, 1, 4>): boolean;
38
50
  /**
39
- * @instance Checks if the current date is a workday (non-weekend day).
51
+ * @instance Checks if the current date is a workday (non-weekend day) using week start day and weekend length.
40
52
  *
41
53
  * @param weekStartsOn Optional. The day index (0–6) that the week starts on. Default is `0` (Sunday).
42
54
  * @param weekendLength Optional. The number of consecutive days at the end of the week considered as weekend. Must be between 1 and 4. Default is `2`.
43
- * @param weekendDays Optional. A tuple of custom weekend day indices (0–6). Its length must match `weekendLength`. If provided, this overrides `weekStartsOn` + `weekendLength` calculation.
44
55
  * @returns `true` if the current date is a work day according to the provided parameters; otherwise `false`.
45
56
  *
46
57
  * @description
@@ -50,13 +61,25 @@ declare module '../Chronos' {
50
61
  * - By default (`weekStartsOn = 0`, `weekendLength = 2`), Saturday (6) and Friday (5) are considered weekend.
51
62
  * - `weekStartsOn` sets the start of the week for calculating weekend days.
52
63
  * - `weekendLength` sets how many days at the end of the week are treated as weekend.
53
- * - `weekendDays`, if provided, is used directly as the weekend days instead of calculating from `weekStartsOn` + `weekendLength`.
54
64
  */
55
- isWorkday<Length extends NumberRange<1, 4>>(weekStartsOn?: Enumerate<7>, weekendLength?: Length, weekendDays?: TupleOf<Enumerate<7>, Length>): boolean;
65
+ isWorkday(weekStartsOn?: Enumerate<7>, weekendLength?: NumberRange<1, 4>): boolean;
56
66
  /**
57
- * @instance Checks if the current date and time fall within business hours.
67
+ * @instance Checks if the current date is a workday (non-weekend day) using indices of weekend days.
68
+ *
69
+ * @param weekendDays A tuple of custom weekend day indices (0–6). Can pass only 1-4 elements.
70
+ * @returns `true` if the current date is a work day according to the provided `weekendDays`; otherwise `false`.
58
71
  *
59
- * @param options Options to configure business hour
72
+ * @description
73
+ * Determines whether the current date is considered as workday. Internally uses {@link isWeekend} method.
74
+ *
75
+ * **Behavior:**
76
+ * - `weekendDays` is used directly as the weekend days instead of calculating from `weekStartsOn` + `weekendLength`.
77
+ */
78
+ isWorkday(weekendDays: RangeTuple<Enumerate<7>, 1, 4>): boolean;
79
+ /**
80
+ * @instance Checks if the current date and time fall within business hours using week start day and weekend length & other options.
81
+ *
82
+ * @param options Options to configure business hour and weekends.
60
83
  *
61
84
  * @returns Whether the current time is within business hours.
62
85
  *
@@ -65,23 +88,29 @@ declare module '../Chronos' {
65
88
  * - Supports standard and overnight business hours. Overnight means `end < start`.
66
89
  * - Example: `businessStartHour = 22`, `businessEndHour = 6` will cover 10 PM to 6 AM next day.
67
90
  *
68
- * * *Weekends are determined by `weekStartsOn` and `weekendLength` or `weekdays` array if provided using the {@link isWeekend} method.*
91
+ * * *Weekends are determined by `weekStartsOn` and `weekendLength` using the {@link isWorkday} method.*
92
+ */
93
+ isBusinessHour(options?: BusinessOptionsBasic): boolean;
94
+ /**
95
+ * @instance Checks if the current date and time fall within business hours using indices of weekend days & other options.
96
+ *
97
+ * @param options Options to configure business hour and weekends.
69
98
  *
70
- * - If you only want to pass `weekendDays` option you should pass the `weekendLength` option or pass a generic (1-4):
71
- * ```ts
72
- * new Chronos().isBusinessHour<3>({ weekendDays: [0, 2, 4] });
99
+ * @returns Whether the current time is within business hours.
73
100
  *
74
- * // Or
101
+ * @remarks
102
+ * - Business hours are typically 9 AM to 5 PM on weekdays.
103
+ * - Supports standard and overnight business hours. Overnight means `end < start`.
104
+ * - Example: `businessStartHour = 22`, `businessEndHour = 6` will cover 10 PM to 6 AM next day.
75
105
  *
76
- * new Chronos().isBusinessHour({weekendLength: 3, weekendDays: [0, 2, 4] });
77
- * ```
106
+ * * *Weekends are determined by `weekendDays` tuple using the {@link isWorkday} method.*
78
107
  */
79
- isBusinessHour<Length extends NumberRange<1, 4>>(options?: BusinessHourOptions<Length>): boolean;
108
+ isBusinessHour(options?: BusinessOptionsWeekends): boolean;
80
109
  /**
81
110
  * @instance Returns the academic year based on a typical start in July and end in June.
82
111
  * @returns The academic year in format `YYYY-YYYY`.
83
112
  */
84
- toAcademicYear(): `${number}-${number}`;
113
+ toAcademicYear(): AcademicYear;
85
114
  /**
86
115
  * @instance Returns the fiscal quarter based on custom fiscal year start (defaults to July).
87
116
  * @param startMonth - The fiscal year start month (1-12), default is July (7).
@@ -1,5 +1,5 @@
1
1
  import type { Enumerate, NumberRange } from '../number/types';
2
- import type { LooseLiteral, TupleOf } from '../utils/types';
2
+ import type { LooseLiteral, RangeTuple } from '../utils/types';
3
3
  import type { Chronos } from './Chronos';
4
4
  import type { ChronosStatics } from './chronos-statics';
5
5
  import type { DATE_FORMATS, DAY_FORMATS, DAYS, HOUR_FORMATS, MILLISECOND_FORMATS, MINUTE_FORMATS, MONTH_FORMATS, MONTHS, SECOND_FORMATS, TIME_FORMATS, TIME_ZONES, WESTERN_ZODIAC_SIGNS, YEAR_FORMATS, ZODIAC_PRESETS } from './constants';
@@ -76,27 +76,46 @@ type DateTimeConnector = ' ' | ', ' | '; ' | ' - ';
76
76
  export type StrictFormat = LooseLiteral<DateParts | TimeParts | `${DateParts}${DateTimeConnector}${TimeParts}`>;
77
77
  /** Iterable `Chronos` object properties */
78
78
  export interface ChronosObject {
79
+ /** Full year (e.g., 2025). */
79
80
  year: number;
81
+ /** Month index starting from 0 (January = 0). */
80
82
  month: Enumerate<12>;
83
+ /** ISO month number starting from 1 (January = 1). */
81
84
  isoMonth: NumberRange<1, 12>;
85
+ /** Day of the month (1–31). */
82
86
  date: NumberRange<1, 31>;
87
+ /** Day of the week index (0–6, Sunday = 0). */
83
88
  weekDay: Enumerate<7>;
89
+ /** ISO day of the week number (1–7, Monday = 1). */
84
90
  isoWeekDay: NumberRange<1, 7>;
91
+ /** Hour of the day (0–23). */
85
92
  hour: Enumerate<24>;
93
+ /** Minute of the hour (0–59). */
86
94
  minute: Enumerate<60>;
95
+ /** Second of the minute (0–59). */
87
96
  second: Enumerate<60>;
97
+ /** Milliseconds within the second. */
88
98
  millisecond: Milliseconds;
99
+ /** Timestamp in milliseconds since the Unix epoch. */
89
100
  timestamp: number;
101
+ /** Unix timestamp in seconds since the epoch. */
90
102
  unix: number;
91
103
  }
92
104
  /** Return object type of `duration` method of `Chronos`. */
93
105
  export interface TimeDuration {
106
+ /** Total number of years. */
94
107
  years: number;
108
+ /** Number of months remaining after full years are counted. */
95
109
  months: number;
110
+ /** Number of days remaining after full months are counted. */
96
111
  days: number;
112
+ /** Number of hours remaining after full days are counted. */
97
113
  hours: number;
114
+ /** Number of minutes remaining after full hours are counted. */
98
115
  minutes: number;
116
+ /** Number of seconds remaining after full minutes are counted. */
99
117
  seconds: number;
118
+ /** Number of milliseconds remaining after full seconds are counted. */
100
119
  milliseconds: number;
101
120
  }
102
121
  /** Interface for accessing internal private properties in extended `Chronos` class */
@@ -184,6 +203,8 @@ export type DayPart = 'night' | 'midnight' | 'lateNight' | 'morning' | 'afternoo
184
203
  export type DayPartConfig = Record<DayPart, [ClockHour, ClockHour]>;
185
204
  /** Quarters of the year */
186
205
  export type Quarter = 1 | 2 | 3 | 4;
206
+ /** Academic year, e.g. `2024-2025` */
207
+ export type AcademicYear = `${number}-${number}`;
187
208
  /** Names of Zodiac signs */
188
209
  export type ZodiacSign = (typeof WESTERN_ZODIAC_SIGNS)[number][0];
189
210
  /** Presets for Zodiac Sign Configuration */
@@ -329,19 +350,26 @@ export interface SeasonOptions {
329
350
  }
330
351
  /** * A plugin that augments the Chronos class with methods or properties. */
331
352
  export type ChronosPlugin = (ChronosClass: $Chronos) => void;
332
- /** Options for configuring business hour */
333
- export interface BusinessHourOptions<Length extends NumberRange<1, 4>> {
353
+ export interface $BusinessHourBaseOptions {
334
354
  /** - Optional starting hour of business time (0–23). Defaults to `9` (9 AM). */
335
355
  businessStartHour?: Enumerate<24>;
336
356
  /** - Optional ending hour of business time (0–23). Defaults to `17` (5 PM). */
337
357
  businessEndHour?: Enumerate<24>;
358
+ }
359
+ /** Options for configuring business hour with `weekStartsOn` and `weekendLength` */
360
+ export interface BusinessOptionsBasic extends $BusinessHourBaseOptions {
338
361
  /** - Optional day the week starts on (0–6). Default is `0` (Sunday). */
339
- weekStartsOn?: Enumerate<7>;
340
- /** - Optional weekend length (1 or 2). Default is `2`.*/
341
- weekendLength?: Length;
342
- /** - Tuple of indices of weekend days. Default is `undefined`. */
343
- weekendDays?: TupleOf<Enumerate<7>, Length>;
362
+ weekStartsOn?: Enumerate<7> | undefined;
363
+ /** - Optional weekend length (1-4). Default is `2`.*/
364
+ weekendLength?: NumberRange<1, 4> | undefined;
344
365
  }
366
+ /** Options for configuring business hour with `weekendDays` tuple */
367
+ export interface BusinessOptionsWeekends extends $BusinessHourBaseOptions {
368
+ /** - Tuple of indices (0-6) of weekend days. Can pass only 1-4 elements. Default is `undefined`. */
369
+ weekendDays?: RangeTuple<Enumerate<7>, 1, 4> | undefined;
370
+ }
371
+ /** Options for configuring business hour */
372
+ export type $BusinessHourOptions = BusinessOptionsBasic | BusinessOptionsWeekends;
345
373
  /** Interface representing a date-like object. */
346
374
  export interface DateLike {
347
375
  toJSON?(): string;
@@ -241,6 +241,18 @@ export type TupleToUnion<T extends readonly unknown[]> = T[number];
241
241
  * type EmptyTuple = TupleOf<boolean, 0>; // []
242
242
  */
243
243
  export type TupleOf<T, N extends number, R extends unknown[] = []> = R['length'] extends N ? R : TupleOf<T, N, [...R, T]>;
244
+ /** * Build a tuple of given length (helper for type-level arithmetic). */
245
+ export type $BuildTuple<L extends number, T extends unknown[] = []> = T['length'] extends L ? T : $BuildTuple<L, [...T, unknown]>;
246
+ /** * Produce a union of numbers `From | From+1 | ... | To`. */
247
+ export type $Range<From extends number, To extends number, Arr extends unknown[] = $BuildTuple<From>, Result = never> = Arr['length'] extends To ? Result | To : $Range<From, To, [...Arr, unknown], Result | Arr['length']>;
248
+ /**
249
+ * * Creates a tuple with length between `Min` and `Max` (inclusive).
250
+ *
251
+ * @example
252
+ * type Ranged = RangeTuple<string, 2, 4>;
253
+ * // Ranged -> [string, string] | [string, string, string] | [string, string, string, string]
254
+ */
255
+ export type RangeTuple<T, Min extends number, Max extends number> = $Range<Min, Max> extends infer N ? N extends number ? TupleOf<T, N> : never : never;
244
256
  /**
245
257
  * * Makes selected or all properties of an object type optional (only the values, not the keys).
246
258
  *
@@ -262,7 +274,7 @@ export type TupleOf<T, N extends number, R extends unknown[] = []> = R['length']
262
274
  export type ValueOptional<O, K extends keyof O = keyof O> = {
263
275
  [P in keyof O]: P extends K ? O[P] | undefined : O[P];
264
276
  };
265
- type $Without<T, U> = {
277
+ export type $Without<T, U> = {
266
278
  [P in Exclude<keyof T, keyof U>]?: never;
267
279
  };
268
280
  /**
@@ -366,14 +378,12 @@ export type RemoveNever<T> = {
366
378
  export type RenameKeys<T, R extends Partial<Record<keyof T, string>>> = {
367
379
  [K in keyof T as K extends keyof R ? Extract<R[K], string | number | symbol> : K]: T[K];
368
380
  };
369
- /** * Build a tuple of given length (helper for type-level arithmetic). */
370
- export type BuildTuple<L extends number, T extends unknown[] = []> = T['length'] extends L ? T : BuildTuple<L, [...T, unknown]>;
371
381
  /** * Subtracts `B` from `A` (helper for type-level arithmetic). */
372
- export type Subtract<A extends number, B extends number> = [
373
- ...BuildTuple<A>
374
- ] extends [...BuildTuple<B>, ...infer R] ? R['length'] : never;
382
+ export type $Subtract<A extends number, B extends number> = [
383
+ ...$BuildTuple<A>
384
+ ] extends [...$BuildTuple<B>, ...infer R] ? R['length'] : never;
375
385
  /** * Forbids all properties not in `K`. */
376
- export type Forbid<T, K extends keyof T> = {
386
+ export type $Forbid<T, K extends keyof T> = {
377
387
  [P in Exclude<keyof T, K>]?: never;
378
388
  };
379
389
  /**
@@ -405,7 +415,7 @@ export type Forbid<T, K extends keyof T> = {
405
415
  export type RequireAtLeast<T extends GenericObject, N extends number, Keys extends keyof T = keyof T> = N extends 1 ? {
406
416
  [K in Keys]-?: Required<Pick<T, K>> & Partial<Omit<T, K>>;
407
417
  }[Keys] : {
408
- [K in Keys]-?: Required<Pick<T, K>> & RequireAtLeast<Omit<T, K>, Subtract<N, 1>>;
418
+ [K in Keys]-?: Required<Pick<T, K>> & RequireAtLeast<Omit<T, K>, $Subtract<N, 1>>;
409
419
  }[Keys];
410
420
  /**
411
421
  * * Enforces that exactly `N` properties of type `T` are required.
@@ -436,7 +446,7 @@ export type RequireAtLeast<T extends GenericObject, N extends number, Keys exten
436
446
  * const c6: TwoExact = { host: "a", port: 1, secure: true }; // ❌ Error
437
447
  */
438
448
  export type RequireExactly<T extends GenericObject, N extends number> = {
439
- [K in keyof T]: Required<Pick<T, K>> & (N extends 1 ? Forbid<T, K> : RequireExactly<Omit<T, K>, Subtract<N, 1>>);
449
+ [K in keyof T]: Required<Pick<T, K>> & (N extends 1 ? $Forbid<T, K> : RequireExactly<Omit<T, K>, $Subtract<N, 1>>);
440
450
  }[keyof T];
441
451
  /**
442
452
  * * Enforces that between `Min` and `Max` properties of type `T` are required.
@@ -459,7 +469,7 @@ export type RequireExactly<T extends GenericObject, N extends number> = {
459
469
  * const s3: OneOrTwo = { theme: "dark", lang: "en", debug: true }; // ❌ (3 keys)
460
470
  * const s4: OneOrTwo = {}; // ❌ (0 keys)
461
471
  */
462
- export type RequireBetween<T extends GenericObject, Min extends number, Max extends number, C extends unknown[] = BuildTuple<Max>, Acc extends unknown[] = BuildTuple<Min>> = RequireExactly<T, Acc['length']> | (Acc['length'] extends Max ? never : RequireBetween<T, Min, Max, C, [...Acc, unknown]>);
472
+ export type RequireBetween<T extends GenericObject, Min extends number, Max extends number, C extends unknown[] = $BuildTuple<Max>, Acc extends unknown[] = $BuildTuple<Min>> = RequireExactly<T, Acc['length']> | (Acc['length'] extends Max ? never : RequireBetween<T, Min, Max, C, [...Acc, unknown]>);
463
473
  /**
464
474
  * * Cast one type to another while preserving compatibility.
465
475
  *
@@ -201,19 +201,20 @@ export class Chronos {
201
201
  }
202
202
  #normalizeDuration(result, absolute, isFuture) {
203
203
  const entries = Object.entries(result);
204
+ const updated = {};
204
205
  if (!absolute && !isFuture) {
205
206
  for (const [key, value] of entries) {
206
207
  if (value !== 0) {
207
- result[key] = value * -1;
208
+ updated[key] = value * -1;
208
209
  }
209
210
  }
210
211
  }
211
212
  else if (absolute) {
212
213
  for (const [key, value] of entries) {
213
- result[key] = Math.abs(value);
214
+ updated[key] = Math.abs(value);
214
215
  }
215
216
  }
216
- return result;
217
+ return updated;
217
218
  }
218
219
  get year() {
219
220
  return this.#date.getFullYear();
@@ -1,34 +1,42 @@
1
1
  import { isValidArray } from '../../guards/non-primitives.js';
2
+ import { isUndefined } from '../../guards/primitives.js';
2
3
  import { INTERNALS } from '../constants.js';
3
4
  export const businessPlugin = (ChronosClass) => {
4
5
  const internalDate = ChronosClass[INTERNALS].internalDate;
5
- ChronosClass.prototype.isWeekend = function (weekStartsOn = 0, weekendLength = 2, weekendDays) {
6
+ ChronosClass.prototype.isWeekend = function (determiner = 0, weekendLength = 2) {
6
7
  const day = internalDate(this).getDay();
7
- if (isValidArray(weekendDays)) {
8
- return weekendDays.includes(day);
8
+ if (isValidArray(determiner)) {
9
+ return determiner.includes(day);
9
10
  }
10
- const lastDayOfWeek = (weekStartsOn + 6) % 7;
11
+ const lastDayOfWeek = (determiner + 6) % 7;
11
12
  const computedWeekendDays = Array.from({ length: weekendLength }, (_, i) => (lastDayOfWeek - i + 7) % 7);
12
13
  return computedWeekendDays.includes(day);
13
14
  };
14
- ChronosClass.prototype.isWorkday = function (weekStartsOn = 0, weekendLength = 2, weekendDays) {
15
- return !this.isWeekend(weekStartsOn, weekendLength, weekendDays);
15
+ ChronosClass.prototype.isWorkday = function (determiner = 0, weekendLength = 2) {
16
+ if (isValidArray(determiner)) {
17
+ return !this.isWeekend(determiner);
18
+ }
19
+ return !this.isWeekend(determiner, weekendLength);
16
20
  };
17
21
  ChronosClass.prototype.isBusinessHour = function (options) {
18
- const { businessStartHour = 9, businessEndHour = 17, weekStartsOn = 0, weekendLength = 2, weekendDays, } = options ?? {};
19
- if (this.isWeekend(weekStartsOn, weekendLength, weekendDays)) {
20
- return false;
21
- }
22
- const hour = internalDate(this).getHours();
23
- if (businessStartHour === businessEndHour) {
24
- return false;
25
- }
26
- if (businessStartHour < businessEndHour) {
27
- return hour >= businessStartHour && hour < businessEndHour;
28
- }
29
- else {
30
- return hour >= businessStartHour || hour < businessEndHour;
22
+ const _isBusinessHour = () => {
23
+ const { businessStartHour = 9, businessEndHour = 17 } = options ?? {};
24
+ if (businessStartHour === businessEndHour) {
25
+ return false;
26
+ }
27
+ const hour = internalDate(this).getHours();
28
+ if (businessStartHour < businessEndHour) {
29
+ return hour >= businessStartHour && hour < businessEndHour;
30
+ }
31
+ else {
32
+ return hour >= businessStartHour || hour < businessEndHour;
33
+ }
34
+ };
35
+ if (options && 'weekendDays' in options && !isUndefined(options?.weekendDays)) {
36
+ return this.isWorkday(options?.weekendDays) && _isBusinessHour();
31
37
  }
38
+ const { weekStartsOn = 0, weekendLength = 2 } = (options ?? {});
39
+ return this.isWorkday(weekStartsOn, weekendLength) && _isBusinessHour();
32
40
  };
33
41
  ChronosClass.prototype.toFiscalQuarter = function (startMonth = 7) {
34
42
  const month = internalDate(this).getMonth() + 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nhb-toolbox",
3
- "version": "4.20.70",
3
+ "version": "4.20.80",
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",