@bereasoftware/time-guard 2.1.0 → 2.2.1
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.en.md +294 -0
- package/README.md +415 -2
- package/dist/calendars/index.es.js +1 -1
- package/dist/locales/index.es.js +1 -1
- package/dist/plugins/advanced-format.es.js +1 -1
- package/dist/plugins/duration.es.js +1 -1
- package/dist/plugins/relative-time.es.js +1 -1
- package/dist/time-guard.cjs +1 -1
- package/dist/time-guard.es.js +545 -135
- package/dist/time-guard.iife.js +1 -1
- package/dist/time-guard.umd.js +1 -1
- package/dist/types/index.d.ts +3 -2
- package/dist/types/time-guard.d.ts +286 -7
- package/dist/types/types/index.d.ts +280 -3
- package/package.json +1 -1
|
@@ -1,16 +1,225 @@
|
|
|
1
|
-
import { ITimeGuard, ITimeGuardConfig, Unit, FormatPreset, IRoundOptions } from './types';
|
|
2
|
-
|
|
1
|
+
import { ITimeGuard, ITimeGuardConfig, Unit, FormatPreset, IRoundOptions, IDurationOptions, IDiffResult, IDiffOptions, DurationParts, IDurationExplanation } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Diff result object that allows chaining with .as()
|
|
4
|
+
* Example: tg1.diff(tg2).as('month')
|
|
5
|
+
* Also acts as a number value for backward compatibility
|
|
6
|
+
*
|
|
7
|
+
* Supports two modes:
|
|
8
|
+
* - 'exact': Returns precise time differences (e.g., 65 days)
|
|
9
|
+
* - 'calendar': Returns calendar-aware breakdown (e.g., 2 months 5 days)
|
|
10
|
+
*/
|
|
11
|
+
declare class DiffResult implements IDiffResult {
|
|
12
|
+
private _value;
|
|
13
|
+
private _tg1;
|
|
14
|
+
private _tg2;
|
|
15
|
+
private _mode;
|
|
16
|
+
private _breakdownData;
|
|
17
|
+
private _locale;
|
|
18
|
+
constructor(value: number, tg1: TimeGuard, tg2: TimeGuard, mode?: 'calendar' | 'exact', breakdownData?: DurationParts, locale?: string);
|
|
19
|
+
/**
|
|
20
|
+
* Convert the diff to a different unit
|
|
21
|
+
* Example: diff.as('month') returns the difference in months
|
|
22
|
+
*/
|
|
23
|
+
as(unit: Unit): number;
|
|
24
|
+
/**
|
|
25
|
+
* Get breakdown in calendar mode (months, days, etc.)
|
|
26
|
+
* Returns null for 'exact' mode
|
|
27
|
+
*/
|
|
28
|
+
breakdown(): DurationParts | null;
|
|
29
|
+
/**
|
|
30
|
+
* Format as human-readable string
|
|
31
|
+
* Example: "2 months and 5 days"
|
|
32
|
+
*/
|
|
33
|
+
format(locale?: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Get the calculation mode used for this diff
|
|
36
|
+
*/
|
|
37
|
+
getMode(): 'calendar' | 'exact';
|
|
38
|
+
/**
|
|
39
|
+
* Allow implicit numeric conversion for backward compatibility
|
|
40
|
+
*/
|
|
41
|
+
valueOf(): number;
|
|
42
|
+
/**
|
|
43
|
+
* String representation
|
|
44
|
+
*/
|
|
45
|
+
toString(): string;
|
|
46
|
+
/**
|
|
47
|
+
* JSON representation
|
|
48
|
+
*/
|
|
49
|
+
toJSON(): number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* DurationResult class - Represents a duration breakdown with humanize support
|
|
53
|
+
* Example: start.until(end).humanize() → "2 months and 5 days"
|
|
54
|
+
*
|
|
55
|
+
* Public class available for type checking and extending
|
|
56
|
+
* Returned by until(), since(), and between() methods
|
|
57
|
+
*/
|
|
58
|
+
export declare class DurationResult implements DurationParts {
|
|
3
59
|
years: number;
|
|
4
60
|
months: number;
|
|
61
|
+
weeks: number;
|
|
5
62
|
days: number;
|
|
6
63
|
hours: number;
|
|
7
64
|
minutes: number;
|
|
8
65
|
seconds: number;
|
|
9
66
|
milliseconds: number;
|
|
10
|
-
|
|
67
|
+
private _locale;
|
|
68
|
+
private _startDate?;
|
|
69
|
+
private _endDate?;
|
|
70
|
+
private _steps;
|
|
71
|
+
private _mode;
|
|
72
|
+
private _leapYearFlags;
|
|
73
|
+
private _calculationTimeMs;
|
|
74
|
+
constructor(parts: DurationParts, locale?: string, metadata?: {
|
|
75
|
+
startDate?: string;
|
|
76
|
+
endDate?: string;
|
|
77
|
+
steps?: string[];
|
|
78
|
+
mode?: 'exact' | 'estimated';
|
|
79
|
+
leapYearFlags?: Array<{
|
|
80
|
+
year: number;
|
|
81
|
+
isLeap: boolean;
|
|
82
|
+
daysInFebruary: number;
|
|
83
|
+
}>;
|
|
84
|
+
calculationTimeMs?: number;
|
|
85
|
+
});
|
|
86
|
+
/**
|
|
87
|
+
* Convert duration to human-readable string
|
|
88
|
+
* Supports multiple humanization styles using Intl API
|
|
89
|
+
* @example
|
|
90
|
+
* duration.humanize() // "2 months" (Intl.RelativeTimeFormat style)
|
|
91
|
+
* duration.humanize({ fullBreakdown: true, locale: 'es' }) // "2 meses y 5 días"
|
|
92
|
+
*/
|
|
93
|
+
humanize(options?: {
|
|
94
|
+
locale?: string;
|
|
95
|
+
fullBreakdown?: boolean;
|
|
96
|
+
numeric?: 'always' | 'auto';
|
|
97
|
+
}): string;
|
|
98
|
+
/**
|
|
99
|
+
* Get total duration in specified unit (date-fns style)
|
|
100
|
+
* Useful for business logic: payments, metrics, analytics
|
|
101
|
+
*
|
|
102
|
+
* Conversion factors:
|
|
103
|
+
* - 1 year = 365.25 days (accounting for leap years)
|
|
104
|
+
* - 1 month = 365.25/12 days = 30.4375 days
|
|
105
|
+
* - 1 week = 7 days
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* duration.total('days') // 65
|
|
109
|
+
* duration.total('months') // 2.166... (65 / 30.4375)
|
|
110
|
+
* duration.total('hours') // 1560 (65 * 24)
|
|
111
|
+
* duration.total('seconds') // 5616000 (65 * 24 * 60 * 60)
|
|
112
|
+
*/
|
|
113
|
+
total(unit: Unit): number;
|
|
114
|
+
/**
|
|
115
|
+
* String representation
|
|
116
|
+
* Returns humanized format by default, or numeric if in exact mode
|
|
117
|
+
*/
|
|
118
|
+
toString(): string;
|
|
119
|
+
/**
|
|
120
|
+
* JSON representation
|
|
121
|
+
* Returns the breakdown as object for serialization
|
|
122
|
+
*/
|
|
123
|
+
toJSON(): Record<string, number>;
|
|
124
|
+
/**
|
|
125
|
+
* Explain the calculation - killer feature for debugging and education
|
|
126
|
+
* Returns detailed breakdown of how the duration was calculated
|
|
127
|
+
*
|
|
128
|
+
* Perfect for:
|
|
129
|
+
* - Debugging complex date calculations
|
|
130
|
+
* - Educational purposes (showing date math)
|
|
131
|
+
* - Auditing time-based business logic
|
|
132
|
+
* - Verification of calculation methodology
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* start.until(end).explain()
|
|
136
|
+
* // {
|
|
137
|
+
* // input: ['2024-01-15', '2024-03-20'],
|
|
138
|
+
* // steps: [
|
|
139
|
+
* // 'Parsed dates: 2024-01-15 to 2024-03-20',
|
|
140
|
+
* // '2024 is a leap year (366 days)',
|
|
141
|
+
* // 'February 2024 has 29 days',
|
|
142
|
+
* // 'Total calculated: 65 days'
|
|
143
|
+
* // ],
|
|
144
|
+
* // breakdown: { years: 0, months: 2, weeks: 0, days: 5, ... },
|
|
145
|
+
* // mode: 'exact',
|
|
146
|
+
* // explanation: 'Calculated 2024-01-15 to 2024-03-20...'
|
|
147
|
+
* // }
|
|
148
|
+
*/
|
|
149
|
+
explain(): IDurationExplanation;
|
|
150
|
+
/**
|
|
151
|
+
* Generate explanation steps for the calculation
|
|
152
|
+
* Used when steps weren't provided during construction
|
|
153
|
+
*/
|
|
154
|
+
private generateExplanationSteps;
|
|
155
|
+
/**
|
|
156
|
+
* Get the conjunction for a locale
|
|
157
|
+
*/
|
|
158
|
+
private getConjunction;
|
|
159
|
+
/**
|
|
160
|
+
* Pluralize a unit name
|
|
161
|
+
*/
|
|
162
|
+
private pluralizeUnit;
|
|
163
|
+
}
|
|
11
164
|
/**
|
|
12
165
|
* TimeGuard implementation - Main facade class
|
|
13
166
|
*/
|
|
167
|
+
/**
|
|
168
|
+
* TimeRange - Fluent API for date range operations
|
|
169
|
+
* Semantic naming that eliminates confusion about date order
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* TimeGuard.range('2024-01-15', '2024-03-20')
|
|
173
|
+
* .toDuration() // Returns DurationResult
|
|
174
|
+
* .humanize() // "2 months and 5 days"
|
|
175
|
+
*
|
|
176
|
+
* TimeGuard.range('2024-01-15', '2024-03-20')
|
|
177
|
+
* .inMonths() // 2.1355 (precise decimal)
|
|
178
|
+
*
|
|
179
|
+
* These methods work regardless of date order
|
|
180
|
+
*/
|
|
181
|
+
export declare class TimeRange {
|
|
182
|
+
private _start;
|
|
183
|
+
private _end;
|
|
184
|
+
constructor(start: TimeGuard, end: TimeGuard);
|
|
185
|
+
/**
|
|
186
|
+
* Get the duration between the two dates
|
|
187
|
+
* @returns DurationResult with all duration properties and methods
|
|
188
|
+
* @example
|
|
189
|
+
* const duration = TimeGuard.range(start, end).toDuration();
|
|
190
|
+
* duration.humanize(); // "2 months and 5 days"
|
|
191
|
+
* duration.total('day'); // 65.875
|
|
192
|
+
*/
|
|
193
|
+
toDuration(): DurationResult;
|
|
194
|
+
/**
|
|
195
|
+
* Get the range expressed in months (as decimal)
|
|
196
|
+
* Accounts for leap years and average month lengths
|
|
197
|
+
* @returns Number of months (can be decimal like 2.1355)
|
|
198
|
+
* @example
|
|
199
|
+
* TimeGuard.range('2024-01-15', '2024-03-20').inMonths(); // ~2.1355
|
|
200
|
+
*/
|
|
201
|
+
inMonths(): number;
|
|
202
|
+
/**
|
|
203
|
+
* Get human-readable representation of the range
|
|
204
|
+
* Semantic naming that emphasizes what the range represents
|
|
205
|
+
* @returns String like "2 months and 5 days"
|
|
206
|
+
* @example
|
|
207
|
+
* TimeGuard.range(start, end).humanize(); // "2 months and 5 days"
|
|
208
|
+
* TimeGuard.range(start, end).humanize({ locale: 'es' }); // "2 meses y 5 días"
|
|
209
|
+
*/
|
|
210
|
+
humanize(options?: {
|
|
211
|
+
locale?: string;
|
|
212
|
+
fullBreakdown?: boolean;
|
|
213
|
+
numeric?: 'always' | 'auto';
|
|
214
|
+
}): string;
|
|
215
|
+
/**
|
|
216
|
+
* Get duration in specific unit
|
|
217
|
+
* Chainable with other TimeRange methods
|
|
218
|
+
* @example
|
|
219
|
+
* TimeGuard.range(start, end).in('day'); // 65.875
|
|
220
|
+
*/
|
|
221
|
+
in(unit: Unit): number;
|
|
222
|
+
}
|
|
14
223
|
export declare class TimeGuard implements ITimeGuard {
|
|
15
224
|
private temporal;
|
|
16
225
|
private config;
|
|
@@ -26,6 +235,43 @@ export declare class TimeGuard implements ITimeGuard {
|
|
|
26
235
|
static from(input: unknown, config?: ITimeGuardConfig): TimeGuard;
|
|
27
236
|
static fromTemporal(temporal: any, // Temporal.PlainDateTime | Temporal.ZonedDateTime
|
|
28
237
|
config?: ITimeGuardConfig): TimeGuard;
|
|
238
|
+
/**
|
|
239
|
+
* Calculate duration between two dates - semantic API eliminating until/since confusion
|
|
240
|
+
*
|
|
241
|
+
* Always returns positive duration regardless of date order.
|
|
242
|
+
* Use .humanize() for user-friendly output.
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* const start = TimeGuard.from("2024-01-15");
|
|
246
|
+
* const end = TimeGuard.from("2024-03-20");
|
|
247
|
+
*
|
|
248
|
+
* TimeGuard.between(start, end).humanize();
|
|
249
|
+
* // "2 months and 5 days"
|
|
250
|
+
*
|
|
251
|
+
* // Order doesn't matter - semantic clarity!
|
|
252
|
+
* TimeGuard.between(end, start).humanize();
|
|
253
|
+
* // "2 months and 5 days" (still positive)
|
|
254
|
+
*
|
|
255
|
+
* // Has all DurationParts properties
|
|
256
|
+
* TimeGuard.between(start, end).months; // 2
|
|
257
|
+
* TimeGuard.between(start, end).days; // 5
|
|
258
|
+
*/
|
|
259
|
+
static between(date1: TimeGuard, date2: TimeGuard): DurationResult;
|
|
260
|
+
/**
|
|
261
|
+
* Create a TimeRange for fluent duration calculations
|
|
262
|
+
* Marketing-friendly naming that emphasizes range semantics
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* TimeGuard.range("2024-01-15", "2024-03-20")
|
|
266
|
+
* .humanize() // "2 months and 5 days"
|
|
267
|
+
*
|
|
268
|
+
* TimeGuard.range("2024-01-15", "2024-03-20")
|
|
269
|
+
* .inMonths() // 2.1355
|
|
270
|
+
*
|
|
271
|
+
* TimeGuard.range("2024-01-15", "2024-03-20")
|
|
272
|
+
* .toDuration() // DurationResult object
|
|
273
|
+
*/
|
|
274
|
+
static range(start: unknown, end: unknown): TimeRange;
|
|
29
275
|
toTemporal(): any;
|
|
30
276
|
toDate(): Date;
|
|
31
277
|
toISOString(): string;
|
|
@@ -41,7 +287,28 @@ export declare class TimeGuard implements ITimeGuard {
|
|
|
41
287
|
get(component: Unit): number;
|
|
42
288
|
add(units: Partial<Record<Unit, number>>): TimeGuard;
|
|
43
289
|
subtract(units: Partial<Record<Unit, number>>): TimeGuard;
|
|
44
|
-
|
|
290
|
+
/**
|
|
291
|
+
* Calculate difference between two TimeGuard instances
|
|
292
|
+
*
|
|
293
|
+
* Supports multiple modes:
|
|
294
|
+
* 1. diff(other) - Returns DiffResult with fluent API (default: exact mode)
|
|
295
|
+
* 2. diff(other, unit) - Returns number (backward compatible)
|
|
296
|
+
* 3. diff(other, options) - Returns DiffResult with calendar or exact mode
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* // Exact mode (default)
|
|
300
|
+
* tg1.diff(tg2).as('day') // Get as number: 65
|
|
301
|
+
*
|
|
302
|
+
* // Calendar mode - shows normalized breakdown
|
|
303
|
+
* tg1.diff(tg2, { mode: 'calendar' }).format('en')
|
|
304
|
+
* // Output: "2 months and 5 days"
|
|
305
|
+
*
|
|
306
|
+
* // With custom unit
|
|
307
|
+
* tg1.diff(tg2, { unit: 'hour' }).as('hour') // 1560
|
|
308
|
+
*/
|
|
309
|
+
diff(other: TimeGuard): DiffResult;
|
|
310
|
+
diff(other: TimeGuard, unit: Unit): number;
|
|
311
|
+
diff(other: TimeGuard, options: IDiffOptions): DiffResult;
|
|
45
312
|
isBefore(other: TimeGuard): boolean;
|
|
46
313
|
isAfter(other: TimeGuard): boolean;
|
|
47
314
|
isSame(other: TimeGuard, unit?: Unit): boolean;
|
|
@@ -65,8 +332,16 @@ export declare class TimeGuard implements ITimeGuard {
|
|
|
65
332
|
inLeapYear(): boolean;
|
|
66
333
|
/**
|
|
67
334
|
* Calculate duration until another TimeGuard
|
|
335
|
+
* @returns Duration object with .humanize() and other methods
|
|
336
|
+
* @example
|
|
337
|
+
* start.until(end).humanize() // "2 months and 5 days"
|
|
338
|
+
* start.until(end).humanize({ fullBreakdown: true, locale: 'es' }) // "2 meses y 5 días"
|
|
339
|
+
*/
|
|
340
|
+
until(other: TimeGuard, options?: IDurationOptions): DurationResult;
|
|
341
|
+
/**
|
|
342
|
+
* Generate explanation steps for until() calculation
|
|
68
343
|
*/
|
|
69
|
-
|
|
344
|
+
private generateUntilSteps;
|
|
70
345
|
/**
|
|
71
346
|
* Round to a specific unit with optional rounding mode
|
|
72
347
|
*/
|
|
@@ -120,8 +395,12 @@ export declare class TimeGuard implements ITimeGuard {
|
|
|
120
395
|
/**
|
|
121
396
|
* Calculate duration from another TimeGuard (inverse of until)
|
|
122
397
|
* Returns negative values if other is before this
|
|
398
|
+
* @returns Duration object with .humanize() and other methods
|
|
399
|
+
* @example
|
|
400
|
+
* end.since(start).humanize() // "2 months and 5 days"
|
|
401
|
+
* end.since(start).humanize({ locale: 'es' }) // "2 meses y 5 días"
|
|
123
402
|
*/
|
|
124
|
-
since(other: TimeGuard):
|
|
403
|
+
since(other: TimeGuard, options?: IDurationOptions): DurationResult;
|
|
125
404
|
/**
|
|
126
405
|
* Get ISO 8601 duration string
|
|
127
406
|
* Example: P1Y2M3DT4H5M6S
|
|
@@ -148,4 +427,4 @@ export declare class TimeGuard implements ITimeGuard {
|
|
|
148
427
|
*/
|
|
149
428
|
isYesterday(): boolean;
|
|
150
429
|
}
|
|
151
|
-
export {};
|
|
430
|
+
export { PluginManager } from './plugins/manager';
|
|
@@ -35,6 +35,230 @@ export interface IRoundOptions {
|
|
|
35
35
|
roundingMode?: 'ceil' | 'floor' | 'expand' | 'trunc' | 'halfExpand' | 'halfFloor' | 'halfCeil' | 'halfTrunc';
|
|
36
36
|
roundingIncrement?: number;
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Duration options for normalizing time differences
|
|
40
|
+
*/
|
|
41
|
+
export interface IDurationOptions {
|
|
42
|
+
largestUnit?: 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond';
|
|
43
|
+
smallestUnit?: 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Diff result object that allows chaining with .as()
|
|
47
|
+
* Example: tg1.diff(tg2).as('month')
|
|
48
|
+
*/
|
|
49
|
+
export interface IDiffResult {
|
|
50
|
+
as(unit: Unit): number;
|
|
51
|
+
/**
|
|
52
|
+
* Get breakdown in calendar mode (e.g., "2 months 5 days")
|
|
53
|
+
* Only available when mode is 'calendar'
|
|
54
|
+
*/
|
|
55
|
+
breakdown(): DurationParts | null;
|
|
56
|
+
/**
|
|
57
|
+
* Format the difference as a human-readable string
|
|
58
|
+
* @param locale Locale code (e.g., 'en', 'es', 'fr')
|
|
59
|
+
* @example
|
|
60
|
+
* diff.format('en') // "2 months and 5 days"
|
|
61
|
+
* diff.format('es') // "2 meses y 5 días"
|
|
62
|
+
*/
|
|
63
|
+
format(locale?: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* Get the mode used for this diff calculation
|
|
66
|
+
*/
|
|
67
|
+
getMode(): 'calendar' | 'exact';
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Options for diff() method
|
|
71
|
+
*/
|
|
72
|
+
export interface IDiffOptions {
|
|
73
|
+
/**
|
|
74
|
+
* Calculation mode:
|
|
75
|
+
* - 'calendar': Returns months/days breakdown (e.g., 65 days → 2 months 5 days)
|
|
76
|
+
* - 'exact': Returns exact time units (e.g., 65 days)
|
|
77
|
+
* @default 'exact'
|
|
78
|
+
*/
|
|
79
|
+
mode?: 'calendar' | 'exact';
|
|
80
|
+
/**
|
|
81
|
+
* Unit for diff when using 'exact' mode
|
|
82
|
+
* @default 'millisecond'
|
|
83
|
+
*/
|
|
84
|
+
unit?: Unit;
|
|
85
|
+
/**
|
|
86
|
+
* Locale for formatting output text
|
|
87
|
+
* @default from TimeGuard instance config
|
|
88
|
+
*/
|
|
89
|
+
locale?: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Duration parts breakdown
|
|
93
|
+
*/
|
|
94
|
+
export interface DurationParts {
|
|
95
|
+
years: number;
|
|
96
|
+
months: number;
|
|
97
|
+
weeks: number;
|
|
98
|
+
days: number;
|
|
99
|
+
hours: number;
|
|
100
|
+
minutes: number;
|
|
101
|
+
seconds: number;
|
|
102
|
+
milliseconds: number;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Options for humanize() method
|
|
106
|
+
*/
|
|
107
|
+
export interface IHumanizeOptions {
|
|
108
|
+
/**
|
|
109
|
+
* Locale code (e.g., 'en', 'es', 'fr')
|
|
110
|
+
* @default from TimeGuard instance config
|
|
111
|
+
*/
|
|
112
|
+
locale?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Show full breakdown (e.g., "2 months and 5 days")
|
|
115
|
+
* or just largest unit (e.g., "2 months")
|
|
116
|
+
* @default false (largest unit only with Intl.RelativeTimeFormat style)
|
|
117
|
+
*/
|
|
118
|
+
fullBreakdown?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Numeric format: 'always', 'auto'
|
|
121
|
+
* @default 'always'
|
|
122
|
+
*/
|
|
123
|
+
numeric?: 'always' | 'auto';
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Duration result with humanize and total methods
|
|
127
|
+
* Returned by until(), since(), and between()
|
|
128
|
+
* Rich object for business logic: payments, metrics, analytics
|
|
129
|
+
*/
|
|
130
|
+
export interface IDurationResult extends DurationParts {
|
|
131
|
+
/**
|
|
132
|
+
* Convert duration to human-readable string
|
|
133
|
+
* @example
|
|
134
|
+
* duration.humanize() // "2 months"
|
|
135
|
+
* duration.humanize({ fullBreakdown: true, locale: 'es' }) // "2 meses y 5 días"
|
|
136
|
+
*/
|
|
137
|
+
humanize(options?: IHumanizeOptions): string;
|
|
138
|
+
/**
|
|
139
|
+
* Get total duration in specified unit (date-fns style)
|
|
140
|
+
* Perfect for business metrics: payments, analytics, calculations
|
|
141
|
+
*
|
|
142
|
+
* Conversion factors account for:
|
|
143
|
+
* - Leap years (1 year = 365.25 days)
|
|
144
|
+
* - Average month length (1 month = 30.4375 days)
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* duration.total('days') // 65
|
|
148
|
+
* duration.total('months') // 2.166... (65 / 30.4375)
|
|
149
|
+
* duration.total('hours') // 1560
|
|
150
|
+
* duration.total('seconds') // 5616000
|
|
151
|
+
*
|
|
152
|
+
* Use cases:
|
|
153
|
+
* - Billing calculations: `duration.total('days') * dailyRate`
|
|
154
|
+
* - Performance metrics: `duration.total('milliseconds')`
|
|
155
|
+
* - Report generation: `duration.total('months')`
|
|
156
|
+
*/
|
|
157
|
+
total(unit: Unit): number;
|
|
158
|
+
/**
|
|
159
|
+
* String representation
|
|
160
|
+
* Returns humanized format for display
|
|
161
|
+
*/
|
|
162
|
+
toString(): string;
|
|
163
|
+
/**
|
|
164
|
+
* JSON representation
|
|
165
|
+
* Returns breakdown as object for API responses
|
|
166
|
+
*/
|
|
167
|
+
toJSON(): Record<string, number>;
|
|
168
|
+
/**
|
|
169
|
+
* Explain the calculation - killer feature for debugging and education
|
|
170
|
+
* Returns detailed breakdown of how the duration was calculated
|
|
171
|
+
*
|
|
172
|
+
* Perfect for:
|
|
173
|
+
* - Debugging complex date calculations
|
|
174
|
+
* - Educational purposes (showing date math)
|
|
175
|
+
* - Auditing time-based business logic
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* duration.explain()
|
|
179
|
+
* // {
|
|
180
|
+
* // input: ['2024-01-15', '2024-03-20'],
|
|
181
|
+
* // steps: ['...step 1...', '...step 2...'],
|
|
182
|
+
* // breakdown: { years: 0, months: 2, days: 5, ... },
|
|
183
|
+
* // mode: 'exact',
|
|
184
|
+
* // explanation: '...'
|
|
185
|
+
* // }
|
|
186
|
+
*/
|
|
187
|
+
explain(): IDurationExplanation;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Duration explanation object for debugging and education
|
|
191
|
+
* Provides transparent insight into calculation methodology
|
|
192
|
+
* Perfect for: debugging, auditing, educational purposes
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* duration.explain()
|
|
196
|
+
* // {
|
|
197
|
+
* // input: ['2024-01-15', '2024-03-20'],
|
|
198
|
+
* // steps: [
|
|
199
|
+
* // 'Parsed dates: 2024-01-15 (day 15 of 365) to 2024-03-20 (day 80 of 365)',
|
|
200
|
+
* // '2024 is a leap year (366 days)',
|
|
201
|
+
* // 'February 2024 has 29 days',
|
|
202
|
+
* // 'Month 1: 31 - 15 = 16 days remaining',
|
|
203
|
+
* // 'Month 2: 29 days (full leap month)',
|
|
204
|
+
* // 'Month 3: 1 - 20 = 20 days',
|
|
205
|
+
* // 'Total: 16 + 29 + 20 = 65 days'
|
|
206
|
+
* // ],
|
|
207
|
+
* // breakdown: { years: 0, months: 2, weeks: 0, days: 5, ... },
|
|
208
|
+
* // mode: 'exact',
|
|
209
|
+
* // explanation: 'Calculated 2024-01-15 to 2024-03-20 including leap year adjustment'
|
|
210
|
+
* // }
|
|
211
|
+
*/
|
|
212
|
+
export interface IDurationExplanation {
|
|
213
|
+
/**
|
|
214
|
+
* Input dates as array of strings or formatted representations
|
|
215
|
+
*/
|
|
216
|
+
input: string[];
|
|
217
|
+
/**
|
|
218
|
+
* Step-by-step calculation explanation
|
|
219
|
+
* Each step is human-readable and educational
|
|
220
|
+
* Useful for debugging complex date calculations
|
|
221
|
+
*/
|
|
222
|
+
steps: string[];
|
|
223
|
+
/**
|
|
224
|
+
* Duration breakdown by component
|
|
225
|
+
* Same as the DurationResult properties
|
|
226
|
+
*/
|
|
227
|
+
breakdown: DurationParts;
|
|
228
|
+
/**
|
|
229
|
+
* Calculation mode
|
|
230
|
+
* - 'exact': Uses Temporal API precise calculations
|
|
231
|
+
* - 'estimated': Fallback for edge cases
|
|
232
|
+
*/
|
|
233
|
+
mode: 'exact' | 'estimated';
|
|
234
|
+
/**
|
|
235
|
+
* Human-readable explanation of the entire calculation
|
|
236
|
+
* Summarizes the approach and any special handling
|
|
237
|
+
*/
|
|
238
|
+
explanation: string;
|
|
239
|
+
/**
|
|
240
|
+
* Locale used for explanation text
|
|
241
|
+
* Supports internationalization of step descriptions
|
|
242
|
+
*/
|
|
243
|
+
locale: string;
|
|
244
|
+
/**
|
|
245
|
+
* Leap year flags if applicable
|
|
246
|
+
* Documents which years were leap years in the calculation
|
|
247
|
+
*/
|
|
248
|
+
leapYearFlags?: {
|
|
249
|
+
year: number;
|
|
250
|
+
isLeap: boolean;
|
|
251
|
+
daysInFebruary: number;
|
|
252
|
+
}[];
|
|
253
|
+
/**
|
|
254
|
+
* Performance metadata
|
|
255
|
+
* For monitoring calculation complexity
|
|
256
|
+
*/
|
|
257
|
+
metadata?: {
|
|
258
|
+
calculationTimeMs: number;
|
|
259
|
+
precision: 'nanosecond' | 'microsecond' | 'millisecond' | 'second' | 'day';
|
|
260
|
+
};
|
|
261
|
+
}
|
|
38
262
|
/**
|
|
39
263
|
* Calendar system interface
|
|
40
264
|
*/
|
|
@@ -110,8 +334,10 @@ export interface ILocaleManager {
|
|
|
110
334
|
export interface IDateArithmetic {
|
|
111
335
|
add(units: Partial<Record<Unit, number>> | IDuration): TimeGuard;
|
|
112
336
|
subtract(units: Partial<Record<Unit, number>> | IDuration): TimeGuard;
|
|
113
|
-
diff(other: TimeGuard
|
|
114
|
-
|
|
337
|
+
diff(other: TimeGuard): IDiffResult;
|
|
338
|
+
diff(other: TimeGuard, unit: Unit): number;
|
|
339
|
+
until(other: TimeGuard, options?: IDurationOptions): IDurationResult;
|
|
340
|
+
since(other: TimeGuard, options?: IDurationOptions): IDurationResult;
|
|
115
341
|
round(options: IRoundOptions): TimeGuard;
|
|
116
342
|
}
|
|
117
343
|
/**
|
|
@@ -250,7 +476,7 @@ export interface ITimeGuard extends IDateArithmetic, IDateQuery, IDateManipulati
|
|
|
250
476
|
/**
|
|
251
477
|
* Duration from another date (inverse of until)
|
|
252
478
|
*/
|
|
253
|
-
since(other: TimeGuard):
|
|
479
|
+
since(other: TimeGuard, options?: IDurationOptions): IDurationResult;
|
|
254
480
|
/**
|
|
255
481
|
* ISO 8601 duration string (P1Y2M3DT4H5M6S)
|
|
256
482
|
*/
|
|
@@ -299,3 +525,54 @@ export interface ITimeGuardFactory {
|
|
|
299
525
|
export declare class TimeGuard {
|
|
300
526
|
constructor(input?: unknown, config?: ITimeGuardConfig);
|
|
301
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* Forward declaration for DurationResult class
|
|
530
|
+
* Implementation is in ./time-guard.ts, exported via ./index.ts
|
|
531
|
+
*/
|
|
532
|
+
export declare class DurationResult implements IDurationResult {
|
|
533
|
+
constructor(parts: DurationParts, locale?: string, metadata?: {
|
|
534
|
+
startDate?: string;
|
|
535
|
+
endDate?: string;
|
|
536
|
+
steps?: string[];
|
|
537
|
+
mode?: 'exact' | 'estimated';
|
|
538
|
+
leapYearFlags?: Array<{
|
|
539
|
+
year: number;
|
|
540
|
+
isLeap: boolean;
|
|
541
|
+
daysInFebruary: number;
|
|
542
|
+
}>;
|
|
543
|
+
calculationTimeMs?: number;
|
|
544
|
+
});
|
|
545
|
+
years: number;
|
|
546
|
+
months: number;
|
|
547
|
+
weeks: number;
|
|
548
|
+
days: number;
|
|
549
|
+
hours: number;
|
|
550
|
+
minutes: number;
|
|
551
|
+
seconds: number;
|
|
552
|
+
milliseconds: number;
|
|
553
|
+
humanize(options?: {
|
|
554
|
+
locale?: string;
|
|
555
|
+
fullBreakdown?: boolean;
|
|
556
|
+
numeric?: 'always' | 'auto';
|
|
557
|
+
}): string;
|
|
558
|
+
total(unit: Unit): number;
|
|
559
|
+
toString(): string;
|
|
560
|
+
toJSON(): Record<string, number>;
|
|
561
|
+
explain(): IDurationExplanation;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Forward declaration for TimeRange class
|
|
565
|
+
* Fluent API for date range operations with semantic naming
|
|
566
|
+
* Implementation is in ./time-guard.ts, exported via ./index.ts
|
|
567
|
+
*/
|
|
568
|
+
export declare class TimeRange {
|
|
569
|
+
constructor(start: TimeGuard, end: TimeGuard);
|
|
570
|
+
toDuration(): DurationResult;
|
|
571
|
+
inMonths(): number;
|
|
572
|
+
humanize(options?: {
|
|
573
|
+
locale?: string;
|
|
574
|
+
fullBreakdown?: boolean;
|
|
575
|
+
numeric?: 'always' | 'auto';
|
|
576
|
+
}): string;
|
|
577
|
+
in(unit: Unit): number;
|
|
578
|
+
}
|