@pvorona/duration 0.1.0 → 0.2.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @pvorona/duration
2
2
 
3
- An immutable duration type with unit conversions, comparisons, and basic arithmetic.
3
+ An immutable ESM-only duration type with unit conversions, comparisons, and basic arithmetic.
4
4
 
5
5
  ## Install
6
6
 
@@ -8,25 +8,44 @@ An immutable duration type with unit conversions, comparisons, and basic arithme
8
8
  npm i @pvorona/duration
9
9
  ```
10
10
 
11
+ This package is ESM-only. Import it from ESM modules instead of `require(...)`.
12
+
11
13
  ## Usage
12
14
 
13
15
  ### Create and convert
14
16
 
15
17
  ```ts
16
- import { minutes } from '@pvorona/duration';
18
+ import { duration, TimeUnit } from '@pvorona/duration';
17
19
 
18
- const d = minutes(5);
19
- d.toSeconds(); // 300
20
- d.toMilliSeconds(); // 300_000
20
+ const d = duration(2, TimeUnit.Minute);
21
+ d.toSeconds(); // 120
22
+ d.toMilliseconds(); // 120_000
23
+ duration(250, TimeUnit.Millisecond).toSeconds(); // 0.25
21
24
  ```
22
25
 
26
+ ### Compose from multiple units
27
+
28
+ ```ts
29
+ import { duration } from '@pvorona/duration';
30
+
31
+ const total = duration({ minutes: 1, seconds: 30 });
32
+ total.toSeconds(); // 90
33
+
34
+ const negative = duration({ hours: -1, minutes: -30 });
35
+ negative.toMilliseconds(); // -5_400_000
36
+ ```
37
+
38
+ `duration(parts)` accepts only the exact plural keys `milliseconds`, `seconds`, `minutes`, `hours`, `days`, `weeks`, `months`, and `years`.
39
+
40
+ All non-zero parts must share the same sign. For example, `duration({ hours: 1, minutes: -30 })` throws `TypeError`.
41
+
23
42
  ### Compare
24
43
 
25
44
  ```ts
26
- import { milliSeconds, seconds } from '@pvorona/duration';
45
+ import { milliseconds, seconds } from '@pvorona/duration';
27
46
 
28
47
  const a = seconds(1);
29
- const b = milliSeconds(900);
48
+ const b = milliseconds(900);
30
49
 
31
50
  a.greaterThan(b); // true
32
51
  a.compare(b); // 1
@@ -35,10 +54,10 @@ a.compare(b); // 1
35
54
  ### Arithmetic
36
55
 
37
56
  ```ts
38
- import { add, milliSeconds, seconds } from '@pvorona/duration';
57
+ import { add, milliseconds, seconds } from '@pvorona/duration';
39
58
 
40
- const total = add(seconds(1), milliSeconds(500));
41
- total.toMilliSeconds(); // 1500
59
+ const total = add(seconds(1), milliseconds(500));
60
+ total.toMilliseconds(); // 1500
42
61
  ```
43
62
 
44
63
  ### Between dates
@@ -51,52 +70,69 @@ const elapsed = since(startedAt);
51
70
  elapsed.toSeconds(); // ~2
52
71
  ```
53
72
 
54
- ## API
73
+ ### Apply a duration to a date
55
74
 
56
- ### `const enum TimeUnit`
75
+ ```ts
76
+ import { addTo, seconds, subtractFrom } from '@pvorona/duration';
57
77
 
58
- Time units supported by `duration(value, unit)` and `d.to(unit)`.
78
+ const start = new Date(1_000);
59
79
 
60
- ```ts
61
- export const enum TimeUnit {
62
- MilliSecond,
63
- Second,
64
- Minute,
65
- Hour,
66
- Day,
67
- Week,
68
- Month,
69
- Year,
70
- }
80
+ addTo(start, seconds(2)).getTime(); // 3_000
81
+ subtractFrom(start, seconds(2)).getTime(); // -1_000
71
82
  ```
72
83
 
73
- Notes:
84
+ ## Important semantics
85
+
86
+ - ESM-only package: use `import`, not `require(...)`.
87
+ - Duration values are frozen branded objects created by this package. Use `isDuration(...)` for unknown inputs instead of duck typing.
88
+ - Compare durations by value with `d.equals(other)` or `isEqual(a, b)`, not `===`.
89
+ - Do not spread, JSON-serialize, or structured-clone `Duration` values as a transport format. Serialize your own explicit shape and reconstruct with `milliseconds(...)` for finite values or `infinite` for the sentinel.
90
+ - `DurationParts` is constructor input only. It is not a serialized `Duration` format and should not be treated as one.
91
+ - `instant` is the exported zero-duration constant, but any zero-valued duration has `isInstant === true`.
92
+ - The public millisecond APIs are `TimeUnit.Millisecond`, `milliseconds(...)`, and `toMilliseconds()`.
93
+ - `Month` is treated as 30 days and `Year` as 365.25 days. These are approximations, not calendar-aware durations.
94
+ - Negative finite durations are valid. `between(...)`, `since(...)`, arithmetic, and comparisons can produce or operate on negative values.
95
+ - Constructors accept only finite numeric inputs. `infinite` is the only supported non-finite duration.
96
+ - `duration(parts)` requires at least one supported plural key, rejects unknown keys, rejects non-finite part values, and rejects mixed-sign non-zero parts.
97
+ - `add(infinite, x)`, `subtract(infinite, finite)`, `multiply(infinite, positive finite)`, and `divide(infinite, positive finite)` return `infinite`.
98
+ - `addTo(date, duration)` and `subtractFrom(date, duration)` do exact timestamp arithmetic equivalent to `new Date(date.getTime() +/- duration.toMilliseconds())`.
99
+ - `addTo(...)` and `subtractFrom(...)` reject invalid dates, reject `infinite`, and reject result timestamps outside the JavaScript `Date` range.
100
+ - `addTo(...)` and `subtractFrom(...)` are timestamp-based, not calendar-aware. Local clock time may shift across DST or timezone offset transitions.
101
+ - `Date` values only have millisecond precision, so the date helpers follow native JavaScript `Date` semantics for fractional-millisecond timestamps.
102
+ - Invalid units, invalid dates, non-finite scalar inputs, divide-by-zero, `subtract(infinite, infinite)`, `subtract(finite, infinite)`, `multiply(infinite, 0)`, `multiply(infinite, negative)`, and `divide(infinite, negative)` throw `TypeError`.
74
103
 
75
- - `Month` is treated as **30 days**
76
- - `Year` is treated as **365.25 days**
104
+ ## API
77
105
 
78
- Example:
106
+ ### `TimeUnit`
79
107
 
80
- ```ts
81
- import { duration, TimeUnit } from '@pvorona/duration';
108
+ The package exports both:
82
109
 
83
- duration(2, TimeUnit.Hour).toMinutes(); // 120
84
- ```
110
+ - `type TimeUnit`: the union of the supported runtime unit values
111
+ - `const TimeUnit`: the runtime constants accepted by `duration(value, unit)` and `d.to(unit)`
112
+
113
+ - `TimeUnit.Millisecond`
114
+ - `TimeUnit.Second`
115
+ - `TimeUnit.Minute`
116
+ - `TimeUnit.Hour`
117
+ - `TimeUnit.Day`
118
+ - `TimeUnit.Week`
119
+ - `TimeUnit.Month`
120
+ - `TimeUnit.Year`
85
121
 
86
122
  ### `type Duration`
87
123
 
88
- An opaque, immutable duration value.
124
+ An opaque, immutable duration value. Duration instances are branded by the package, so use `isDuration(...)` for unknown inputs and compare values with `equals(...)` / `isEqual(...)` rather than `===`.
89
125
 
90
126
  #### Properties
91
127
 
92
- - **`isFinite: boolean`**: `true` unless the duration is infinite
93
- - **`isInfinite: boolean`**: `true` for `infinite`
94
- - **`isInstant: boolean`**: `true` for zero duration (`instant`)
128
+ - **`isFinite: boolean`**: `true` for finite durations
129
+ - **`isInfinite: boolean`**: `true` only for `infinite`
130
+ - **`isInstant: boolean`**: `true` for any zero duration (including `instant`)
95
131
 
96
132
  #### Conversions
97
133
 
98
134
  - **`to(unit: TimeUnit): number`**: convert to an arbitrary unit
99
- - **`toMilliSeconds(): number`**
135
+ - **`toMilliseconds(): number`**
100
136
  - **`toSeconds(): number`**
101
137
  - **`toMinutes(): number`**
102
138
  - **`toHours(): number`**
@@ -114,28 +150,44 @@ An opaque, immutable duration value.
114
150
  - **`greaterThanOrEqual(other: Duration): boolean`**
115
151
  - **`compare(other: Duration): -1 | 0 | 1`**
116
152
 
117
- Example (properties + conversion + comparison):
153
+ Example:
118
154
 
119
155
  ```ts
120
- import { milliSeconds, seconds, type Duration } from '@pvorona/duration';
156
+ import { milliseconds, seconds, type Duration } from '@pvorona/duration';
121
157
 
122
158
  function isShort(d: Duration) {
123
159
  return d.isFinite && d.toSeconds() < 5;
124
160
  }
125
161
 
126
162
  const a = seconds(1);
127
- const b = milliSeconds(900);
163
+ const b = milliseconds(900);
128
164
 
129
165
  isShort(a); // true
130
166
  a.greaterThan(b); // true
131
167
  ```
132
168
 
169
+ ### `type DurationParts`
170
+
171
+ Strict constructor input for `duration(parts)`. Supported keys:
172
+
173
+ - `milliseconds?: number`
174
+ - `seconds?: number`
175
+ - `minutes?: number`
176
+ - `hours?: number`
177
+ - `days?: number`
178
+ - `weeks?: number`
179
+ - `months?: number`
180
+ - `years?: number`
181
+
182
+ At least one key is required. All non-zero keys must share the same sign.
183
+
133
184
  ### Function API
134
185
 
135
186
  #### Constructors
136
187
 
137
188
  - `duration(value: number, unit: TimeUnit): Duration`
138
- - `milliSeconds(value: number): Duration`
189
+ - `duration(parts: DurationParts): Duration`
190
+ - `milliseconds(value: number): Duration`
139
191
  - `seconds(value: number): Duration`
140
192
  - `minutes(value: number): Duration`
141
193
  - `hours(value: number): Duration`
@@ -148,6 +200,8 @@ a.greaterThan(b); // true
148
200
 
149
201
  - `between(start: Date, end: Date): Duration`
150
202
  - `since(start: Date): Duration`
203
+ - `addTo(date: Date, duration: Duration): Date`
204
+ - `subtractFrom(date: Date, duration: Duration): Date`
151
205
 
152
206
  #### Arithmetic helpers
153
207
 
@@ -173,6 +227,6 @@ import { isDuration, seconds } from '@pvorona/duration';
173
227
 
174
228
  const maybe: unknown = seconds(1);
175
229
  if (isDuration(maybe)) {
176
- maybe.toMilliSeconds(); // ok, narrowed
230
+ maybe.toMilliseconds(); // ok, narrowed
177
231
  }
178
232
  ```
package/dist/index.js CHANGED
@@ -1,205 +1,256 @@
1
- import { isObject as i } from "@pvorona/assert";
2
- var c = /* @__PURE__ */ ((t) => (t[t.MilliSecond = 0] = "MilliSecond", t[t.Second = 1] = "Second", t[t.Minute = 2] = "Minute", t[t.Hour = 3] = "Hour", t[t.Day = 4] = "Day", t[t.Week = 5] = "Week", t[t.Month = 6] = "Month", t[t.Year = 7] = "Year", t))(c || {});
3
- const n = /* @__PURE__ */ Symbol("milliSeconds"), o = {
4
- 0: 1,
5
- 1: 1e3,
6
- 2: 60 * 1e3,
7
- 3: 3600 * 1e3,
1
+ import { isObject as T, hasOwnKey as b } from "@pvorona/assert";
2
+ const N = {
3
+ Millisecond: 0,
4
+ Second: 1,
5
+ Minute: 2,
6
+ Hour: 3,
7
+ Day: 4,
8
+ Week: 5,
9
+ Month: 6,
10
+ Year: 7
11
+ }, e = N, w = {
12
+ milliseconds: e.Millisecond,
13
+ seconds: e.Second,
14
+ minutes: e.Minute,
15
+ hours: e.Hour,
16
+ days: e.Day,
17
+ weeks: e.Week,
18
+ months: e.Month,
19
+ years: e.Year
20
+ }, r = /* @__PURE__ */ Symbol("milliseconds"), D = new Set(Object.values(e)), S = new Set(
21
+ Object.keys(w)
22
+ ), d = {
23
+ [e.Millisecond]: 1,
24
+ [e.Second]: 1e3,
25
+ [e.Minute]: 60 * 1e3,
26
+ [e.Hour]: 3600 * 1e3,
8
27
  /** Note: Does not account for leap second */
9
- 4: 1440 * 60 * 1e3,
10
- 5: 10080 * 60 * 1e3,
28
+ [e.Day]: 1440 * 60 * 1e3,
29
+ [e.Week]: 10080 * 60 * 1e3,
11
30
  /** Note: Does not account for leap year */
12
- 6: (
31
+ [e.Month]: (
13
32
  /* 30 days */
14
33
  720 * 60 * 60 * 1e3
15
34
  ),
16
35
  /** Note: Does not account for leap year */
17
- 7: (
36
+ [e.Year]: (
18
37
  /* 365.25 days */
19
38
  365.25 * 24 * 60 * 60 * 1e3
20
39
  )
21
- }, a = {
22
- [n]: 0,
40
+ };
41
+ function p(n) {
42
+ if (D.has(n))
43
+ return n;
44
+ throw new TypeError("Expected a valid time unit.");
45
+ }
46
+ function c(n, t) {
47
+ if (Number.isFinite(n))
48
+ return n;
49
+ throw new TypeError(`Expected \`${t}\` to be finite.`);
50
+ }
51
+ function a(n, t) {
52
+ const i = n.getTime();
53
+ if (!Number.isNaN(i))
54
+ return i;
55
+ throw new TypeError(`Expected \`${t}\` to be a valid date.`);
56
+ }
57
+ function y(n, t) {
58
+ const i = new Date(n);
59
+ return a(i, t), i;
60
+ }
61
+ function g(n) {
62
+ if (S.has(n))
63
+ return n;
64
+ throw new TypeError(`Expected \`${n}\` to be a supported duration part.`);
65
+ }
66
+ function _(n) {
67
+ const t = Object.entries(n);
68
+ if (t.length === 0)
69
+ throw new TypeError("Expected `parts` to include at least one duration part.");
70
+ let i = 0, o;
71
+ for (const [E, M] of t) {
72
+ const h = g(E), l = c(M, `parts.${h}`);
73
+ if (l === 0)
74
+ continue;
75
+ const m = Math.sign(l);
76
+ if (o == null && (o = m), o !== m)
77
+ throw new TypeError("Expected non-zero duration parts to share the same sign.");
78
+ i += l * d[w[h]];
79
+ }
80
+ return i;
81
+ }
82
+ function O(n, t) {
83
+ if (Number.isNaN(n) || n === Number.NEGATIVE_INFINITY)
84
+ throw new TypeError("Expected duration milliseconds to be finite or `Infinity`.");
85
+ if (n !== 1 / 0 || t?.allowInfinite)
86
+ return n;
87
+ throw new TypeError("Expected duration milliseconds to be finite.");
88
+ }
89
+ const U = {
90
+ [r]: 0,
23
91
  isFinite: !1,
24
92
  isInfinite: !1,
25
93
  isInstant: !1,
26
- to(t) {
27
- return this[n] / o[t];
94
+ to(n) {
95
+ return this[r] / d[p(n)];
28
96
  },
29
- toMilliSeconds() {
30
- return this.to(
31
- 0
32
- /* MilliSecond */
33
- );
97
+ toMilliseconds() {
98
+ return this.to(e.Millisecond);
34
99
  },
35
100
  toSeconds() {
36
- return this.to(
37
- 1
38
- /* Second */
39
- );
101
+ return this.to(e.Second);
40
102
  },
41
103
  toMinutes() {
42
- return this.to(
43
- 2
44
- /* Minute */
45
- );
104
+ return this.to(e.Minute);
46
105
  },
47
106
  toHours() {
48
- return this.to(
49
- 3
50
- /* Hour */
51
- );
107
+ return this.to(e.Hour);
52
108
  },
53
109
  toDays() {
54
- return this.to(
55
- 4
56
- /* Day */
57
- );
110
+ return this.to(e.Day);
58
111
  },
59
112
  toWeeks() {
60
- return this.to(
61
- 5
62
- /* Week */
63
- );
113
+ return this.to(e.Week);
64
114
  },
65
115
  toMonths() {
66
- return this.to(
67
- 6
68
- /* Month */
69
- );
116
+ return this.to(e.Month);
70
117
  },
71
118
  toYears() {
72
- return this.to(
73
- 7
74
- /* Year */
75
- );
119
+ return this.to(e.Year);
76
120
  },
77
- equals(t) {
78
- return this[n] === t[n];
121
+ equals(n) {
122
+ return this[r] === n[r];
79
123
  },
80
- lessThan(t) {
81
- return this[n] < t[n];
124
+ lessThan(n) {
125
+ return this[r] < n[r];
82
126
  },
83
- lessThanOrEqual(t) {
84
- return this[n] <= t[n];
127
+ lessThanOrEqual(n) {
128
+ return this[r] <= n[r];
85
129
  },
86
- greaterThan(t) {
87
- return this[n] > t[n];
130
+ greaterThan(n) {
131
+ return this[r] > n[r];
88
132
  },
89
- greaterThanOrEqual(t) {
90
- return this[n] >= t[n];
133
+ greaterThanOrEqual(n) {
134
+ return this[r] >= n[r];
91
135
  },
92
- compare(t) {
93
- return this.lessThan(t) ? -1 : this.greaterThan(t) ? 1 : 0;
136
+ compare(n) {
137
+ return this.lessThan(n) ? -1 : this.greaterThan(n) ? 1 : 0;
94
138
  }
95
139
  };
96
- function f(t, r) {
97
- const s = Object.create(a);
98
- return s[n] = t * o[r], s.isFinite = t !== 1 / 0, s.isInfinite = t === 1 / 0, s.isInstant = t === 0, Object.freeze(s);
99
- }
100
- function e(t, r) {
101
- return f(t, r);
102
- }
103
- function u(t) {
104
- return e(
105
- t,
106
- 0
107
- /* MilliSecond */
108
- );
140
+ function s(n, t) {
141
+ const i = O(n, t), o = Object.create(U);
142
+ return o[r] = i, o.isFinite = Number.isFinite(i), o.isInfinite = i === 1 / 0, o.isInstant = i === 0, Object.freeze(o);
109
143
  }
110
- function d(t) {
111
- return e(
112
- t,
113
- 1
114
- /* Second */
115
- );
144
+ function u(n, t) {
145
+ if (T(n))
146
+ return s(_(n));
147
+ const i = c(n, "value"), o = p(t);
148
+ return s(i * d[o]);
116
149
  }
117
- function I(t) {
118
- return e(
119
- t,
120
- 2
121
- /* Minute */
122
- );
150
+ function x(n) {
151
+ return u(n, e.Millisecond);
123
152
  }
124
- function S(t) {
125
- return e(
126
- t,
127
- 3
128
- /* Hour */
129
- );
153
+ function z(n) {
154
+ return u(n, e.Second);
130
155
  }
131
- function y(t) {
132
- return e(
133
- t,
134
- 4
135
- /* Day */
136
- );
156
+ function A(n) {
157
+ return u(n, e.Minute);
137
158
  }
138
- function M(t) {
139
- return e(
140
- t,
141
- 5
142
- /* Week */
143
- );
159
+ function Y(n) {
160
+ return u(n, e.Hour);
144
161
  }
145
- function D(t) {
146
- return e(
147
- t,
148
- 6
149
- /* Month */
150
- );
162
+ function v(n) {
163
+ return u(n, e.Day);
151
164
  }
152
- function O(t) {
153
- return e(
154
- t,
155
- 7
156
- /* Year */
157
- );
165
+ function j(n) {
166
+ return u(n, e.Week);
167
+ }
168
+ function C(n) {
169
+ return u(n, e.Month);
158
170
  }
159
- function h(t, r) {
160
- return u(r.getTime() - t.getTime());
171
+ function H(n) {
172
+ return u(n, e.Year);
161
173
  }
162
- function b(t) {
163
- return h(t, /* @__PURE__ */ new Date());
174
+ function F(n, t) {
175
+ const i = a(n, "start"), o = a(t, "end");
176
+ return s(o - i);
164
177
  }
165
- function g(t, r) {
166
- return u(t[n] + r[n]);
178
+ function V(n) {
179
+ return F(n, /* @__PURE__ */ new Date());
180
+ }
181
+ function I(n) {
182
+ if (!n.isInfinite)
183
+ return n.toMilliseconds();
184
+ throw new TypeError("Expected `duration` to be finite.");
185
+ }
186
+ function W(n, t) {
187
+ return n.isInfinite || t.isInfinite ? f : s(n[r] + t[r]);
188
+ }
189
+ function R(n, t) {
190
+ if (n.isInfinite && t.isInfinite)
191
+ throw new TypeError("Cannot subtract `infinite` from `infinite`.");
192
+ if (n.isInfinite)
193
+ return f;
194
+ if (t.isInfinite)
195
+ throw new TypeError("Cannot subtract `infinite` from a finite duration.");
196
+ return s(n[r] - t[r]);
197
+ }
198
+ function q(n, t) {
199
+ const i = c(t, "multiplier");
200
+ if (!n.isInfinite)
201
+ return s(n[r] * i);
202
+ if (i > 0)
203
+ return f;
204
+ throw new TypeError(
205
+ "Cannot multiply `infinite` by zero or a negative number."
206
+ );
167
207
  }
168
- function E(t, r) {
169
- return u(t[n] - r[n]);
208
+ function K(n, t) {
209
+ const i = c(t, "divisor");
210
+ if (i === 0)
211
+ throw new TypeError("Cannot divide by zero.");
212
+ if (!n.isInfinite)
213
+ return s(n[r] / i);
214
+ if (i > 0)
215
+ return f;
216
+ throw new TypeError("Cannot divide `infinite` by a negative number.");
170
217
  }
171
- function k(t, r) {
172
- return u(t[n] * r);
218
+ function $(n, t) {
219
+ const i = a(n, "date"), o = I(t);
220
+ return y(i + o, "result");
173
221
  }
174
- function p(t, r) {
175
- return u(t[n] / r);
222
+ function L(n, t) {
223
+ const i = a(n, "date"), o = I(t);
224
+ return y(i - o, "result");
176
225
  }
177
- const q = u(1 / 0), N = u(0);
178
- function j(t) {
179
- return i(t) && n in t;
226
+ const f = s(1 / 0, { allowInfinite: !0 }), P = x(0);
227
+ function B(n) {
228
+ return T(n) && b(n, r);
180
229
  }
181
- function w(t, r) {
182
- return t[n] === r[n];
230
+ function G(n, t) {
231
+ return n[r] === t[r];
183
232
  }
184
233
  export {
185
- c as TimeUnit,
186
- g as add,
187
- h as between,
188
- y as days,
189
- p as divide,
190
- e as duration,
191
- S as hours,
192
- q as infinite,
193
- N as instant,
194
- j as isDuration,
195
- w as isEqual,
196
- u as milliSeconds,
197
- I as minutes,
198
- D as months,
199
- k as multiply,
200
- d as seconds,
201
- b as since,
202
- E as subtract,
203
- M as weeks,
204
- O as years
234
+ e as TimeUnit,
235
+ W as add,
236
+ $ as addTo,
237
+ F as between,
238
+ v as days,
239
+ K as divide,
240
+ u as duration,
241
+ Y as hours,
242
+ f as infinite,
243
+ P as instant,
244
+ B as isDuration,
245
+ G as isEqual,
246
+ x as milliseconds,
247
+ A as minutes,
248
+ C as months,
249
+ q as multiply,
250
+ z as seconds,
251
+ V as since,
252
+ R as subtract,
253
+ L as subtractFrom,
254
+ j as weeks,
255
+ H as years
205
256
  };
@@ -1,21 +1,50 @@
1
- export declare const enum TimeUnit {
2
- MilliSecond = 0,
3
- Second = 1,
4
- Minute = 2,
5
- Hour = 3,
6
- Day = 4,
7
- Week = 5,
8
- Month = 6,
9
- Year = 7
10
- }
1
+ declare const TIME_UNIT_VALUES: {
2
+ readonly Millisecond: 0;
3
+ readonly Second: 1;
4
+ readonly Minute: 2;
5
+ readonly Hour: 3;
6
+ readonly Day: 4;
7
+ readonly Week: 5;
8
+ readonly Month: 6;
9
+ readonly Year: 7;
10
+ };
11
+ /** Supported runtime unit values used by `TimeUnit`. */
12
+ export type TimeUnit = (typeof TIME_UNIT_VALUES)[keyof typeof TIME_UNIT_VALUES];
13
+ /**
14
+ * Runtime time-unit constants accepted by `duration(value, unit)` and `d.to(unit)`.
15
+ *
16
+ * `Month` uses a 30-day approximation and `Year` uses a 365.25-day approximation.
17
+ */
18
+ export declare const TimeUnit: {
19
+ readonly [Key in keyof typeof TIME_UNIT_VALUES]: TimeUnit;
20
+ };
21
+ declare const DURATION_PART_TIME_UNITS: {
22
+ readonly milliseconds: TimeUnit;
23
+ readonly seconds: TimeUnit;
24
+ readonly minutes: TimeUnit;
25
+ readonly hours: TimeUnit;
26
+ readonly days: TimeUnit;
27
+ readonly weeks: TimeUnit;
28
+ readonly months: TimeUnit;
29
+ readonly years: TimeUnit;
30
+ };
31
+ type DurationPartKey = keyof typeof DURATION_PART_TIME_UNITS;
32
+ type RequireAtLeastOne<T> = {
33
+ [Key in keyof T]-?: Required<Pick<T, Key>> & Partial<Omit<T, Key>>;
34
+ }[keyof T];
35
+ /** Input bag accepted by `duration(parts)` for strict multi-unit construction. */
36
+ export type DurationParts = RequireAtLeastOne<{
37
+ readonly [Key in DurationPartKey]?: number;
38
+ }>;
11
39
  declare const millisecondsTag: unique symbol;
40
+ /** Immutable duration value with conversions, comparisons, and state flags. */
12
41
  export type Duration = {
13
42
  readonly [millisecondsTag]: number;
14
43
  readonly isFinite: boolean;
15
44
  readonly isInfinite: boolean;
16
45
  readonly isInstant: boolean;
17
46
  to(unit: TimeUnit): number;
18
- toMilliSeconds(): number;
47
+ toMilliseconds(): number;
19
48
  toSeconds(): number;
20
49
  toMinutes(): number;
21
50
  toHours(): number;
@@ -30,24 +59,49 @@ export type Duration = {
30
59
  greaterThanOrEqual(other: Duration): boolean;
31
60
  compare(other: Duration): -1 | 0 | 1;
32
61
  };
62
+ /** Creates a duration from a finite numeric value in the provided unit. */
33
63
  export declare function duration(value: number, unit: TimeUnit): Duration;
34
- export declare function milliSeconds(value: number): Duration;
64
+ /** Creates a duration from strict multi-unit parts. */
65
+ export declare function duration(parts: DurationParts): Duration;
66
+ /** Creates a duration from a finite millisecond value. */
67
+ export declare function milliseconds(value: number): Duration;
68
+ /** Creates a duration from a finite second value. */
35
69
  export declare function seconds(value: number): Duration;
70
+ /** Creates a duration from a finite minute value. */
36
71
  export declare function minutes(value: number): Duration;
72
+ /** Creates a duration from a finite hour value. */
37
73
  export declare function hours(value: number): Duration;
74
+ /** Creates a duration from a finite day value. */
38
75
  export declare function days(value: number): Duration;
76
+ /** Creates a duration from a finite week value. */
39
77
  export declare function weeks(value: number): Duration;
78
+ /** Creates a duration from a finite approximate month value (30 days each). */
40
79
  export declare function months(value: number): Duration;
80
+ /** Creates a duration from a finite approximate year value (365.25 days each). */
41
81
  export declare function years(value: number): Duration;
82
+ /** Returns the duration between two valid dates. The result may be negative. */
42
83
  export declare function between(start: Date, end: Date): Duration;
84
+ /** Returns the duration since a valid start date. The result may be negative. */
43
85
  export declare function since(start: Date): Duration;
86
+ /** Adds two durations and preserves the explicit `infinite` sentinel. */
44
87
  export declare function add(a: Duration, b: Duration): Duration;
88
+ /** Subtracts one duration from another and rejects undefined `infinite` cases. */
45
89
  export declare function subtract(a: Duration, b: Duration): Duration;
90
+ /** Multiplies a duration by a finite scalar. */
46
91
  export declare function multiply(a: Duration, b: number): Duration;
92
+ /** Divides a duration by a finite, non-zero scalar. */
47
93
  export declare function divide(a: Duration, b: number): Duration;
94
+ /** Returns a new date shifted forward by an exact duration timestamp delta. */
95
+ export declare function addTo(date: Date, duration: Duration): Date;
96
+ /** Returns a new date shifted backward by an exact duration timestamp delta. */
97
+ export declare function subtractFrom(date: Date, duration: Duration): Date;
98
+ /** The explicit non-finite duration sentinel supported by this package. */
48
99
  export declare const infinite: Duration;
100
+ /** The zero-length duration constant. */
49
101
  export declare const instant: Duration;
102
+ /** Returns `true` when the value is a duration created by this package. */
50
103
  export declare function isDuration(value: unknown): value is Duration;
104
+ /** Compares two durations by their normalized millisecond payload. */
51
105
  export declare function isEqual(a: Duration, b: Duration): boolean;
52
106
  export {};
53
107
  //# sourceMappingURL=duration.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"duration.d.ts","sourceRoot":"","sources":["../../src/lib/duration.ts"],"names":[],"mappings":"AAMA,0BAAkB,QAAQ;IACxB,WAAW,IAAA;IACX,MAAM,IAAA;IACN,MAAM,IAAA;IACN,IAAI,IAAA;IACJ,GAAG,IAAA;IACH,IAAI,IAAA;IACJ,KAAK,IAAA;IACL,IAAI,IAAA;CACL;AAED,QAAA,MAAM,eAAe,eAAyB,CAAC;AAE/C,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC3B,cAAc,IAAI,MAAM,CAAC;IACzB,SAAS,IAAI,MAAM,CAAC;IACpB,SAAS,IAAI,MAAM,CAAC;IACpB,OAAO,IAAI,MAAM,CAAC;IAClB,MAAM,IAAI,MAAM,CAAC;IACjB,OAAO,IAAI,MAAM,CAAC;IAClB,QAAQ,IAAI,MAAM,CAAC;IACnB,OAAO,IAAI,MAAM,CAAC;IAElB,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;IACnC,eAAe,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC1C,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;IACtC,kBAAkB,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC7C,OAAO,CAAC,KAAK,EAAE,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CACtC,CAAC;AAoFF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAEhE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAEpD;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE/C;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE/C;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE7C;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE5C;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE7C;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE9C;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE7C;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,QAAQ,CAExD;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,IAAI,GAAG,QAAQ,CAE3C;AAED,wBAAgB,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAEtD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAE3D;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,GAAG,QAAQ,CAEzD;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,GAAG,QAAQ,CAEvD;AAED,eAAO,MAAM,QAAQ,EAAE,QAAiC,CAAC;AACzD,eAAO,MAAM,OAAO,EAAE,QAA0B,CAAC;AAEjD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAEzD"}
1
+ {"version":3,"file":"duration.d.ts","sourceRoot":"","sources":["../../src/lib/duration.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pvorona/duration",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -9,7 +9,6 @@
9
9
  "exports": {
10
10
  "./package.json": "./package.json",
11
11
  ".": {
12
- "@pvorona/source": "./src/index.ts",
13
12
  "types": "./dist/index.d.ts",
14
13
  "import": "./dist/index.js",
15
14
  "default": "./dist/index.js"
@@ -19,10 +18,15 @@
19
18
  "dist",
20
19
  "!**/*.tsbuildinfo"
21
20
  ],
21
+ "scripts": {
22
+ "check-consumer-types": "node ./scripts/check-consumer-types.mjs",
23
+ "check-package-surface": "node ./scripts/check-package-surface.mjs",
24
+ "prepublishOnly": "npm run check-consumer-types && npm run check-package-surface"
25
+ },
22
26
  "publishConfig": {
23
27
  "access": "public"
24
28
  },
25
29
  "dependencies": {
26
- "@pvorona/assert": "~0.0.2"
30
+ "@pvorona/assert": "~0.1.0"
27
31
  }
28
32
  }