@bcts/dcbor 1.0.0-alpha.10
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/LICENSE +48 -0
- package/README.md +13 -0
- package/dist/index.cjs +9151 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3107 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +3107 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.iife.js +9155 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.mjs +9027 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +80 -0
- package/src/.claude-flow/metrics/agent-metrics.json +1 -0
- package/src/.claude-flow/metrics/performance.json +87 -0
- package/src/.claude-flow/metrics/task-metrics.json +10 -0
- package/src/byte-string.ts +300 -0
- package/src/cbor-codable.ts +170 -0
- package/src/cbor-tagged-codable.ts +72 -0
- package/src/cbor-tagged-decodable.ts +184 -0
- package/src/cbor-tagged-encodable.ts +138 -0
- package/src/cbor-tagged.ts +104 -0
- package/src/cbor.ts +869 -0
- package/src/conveniences.ts +840 -0
- package/src/date.ts +553 -0
- package/src/decode.ts +276 -0
- package/src/diag.ts +462 -0
- package/src/dump.ts +277 -0
- package/src/error.ts +259 -0
- package/src/exact.ts +714 -0
- package/src/float.ts +279 -0
- package/src/global.d.ts +34 -0
- package/src/globals.d.ts +0 -0
- package/src/index.ts +180 -0
- package/src/map.ts +308 -0
- package/src/prelude.ts +70 -0
- package/src/set.ts +515 -0
- package/src/simple.ts +153 -0
- package/src/stdlib.ts +55 -0
- package/src/string-util.ts +55 -0
- package/src/tag.ts +53 -0
- package/src/tags-store.ts +294 -0
- package/src/tags.ts +231 -0
- package/src/varint.ts +124 -0
- package/src/walk.ts +516 -0
package/src/date.ts
ADDED
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Date/time support for CBOR with tag(1) encoding.
|
|
3
|
+
*
|
|
4
|
+
* A CBOR-friendly representation of a date and time.
|
|
5
|
+
*
|
|
6
|
+
* The `CborDate` type provides a wrapper around JavaScript's native `Date` that
|
|
7
|
+
* supports encoding and decoding to/from CBOR with tag 1, following the CBOR
|
|
8
|
+
* date/time standard specified in RFC 8949.
|
|
9
|
+
*
|
|
10
|
+
* When encoded to CBOR, dates are represented as tag 1 followed by a numeric
|
|
11
|
+
* value representing the number of seconds since (or before) the Unix epoch
|
|
12
|
+
* (1970-01-01T00:00:00Z). The numeric value can be a positive or negative
|
|
13
|
+
* integer, or a floating-point value for dates with fractional seconds.
|
|
14
|
+
*
|
|
15
|
+
* @module date
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { type Cbor, MajorType } from "./cbor";
|
|
19
|
+
import { cbor } from "./cbor";
|
|
20
|
+
import { createTag, type Tag } from "./tag";
|
|
21
|
+
import { TAG_EPOCH_DATE_TIME } from "./tags";
|
|
22
|
+
import {
|
|
23
|
+
type CborTaggedEncodable,
|
|
24
|
+
type CborTaggedDecodable,
|
|
25
|
+
type CborTagged,
|
|
26
|
+
createTaggedCbor,
|
|
27
|
+
validateTag,
|
|
28
|
+
extractTaggedContent,
|
|
29
|
+
} from "./cbor-tagged";
|
|
30
|
+
import { CborError } from "./error";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A CBOR-friendly representation of a date and time.
|
|
34
|
+
*
|
|
35
|
+
* The `CborDate` type provides a wrapper around JavaScript's native `Date` that
|
|
36
|
+
* supports encoding and decoding to/from CBOR with tag 1, following the CBOR
|
|
37
|
+
* date/time standard specified in RFC 8949.
|
|
38
|
+
*
|
|
39
|
+
* When encoded to CBOR, dates are represented as tag 1 followed by a numeric
|
|
40
|
+
* value representing the number of seconds since (or before) the Unix epoch
|
|
41
|
+
* (1970-01-01T00:00:00Z). The numeric value can be a positive or negative
|
|
42
|
+
* integer, or a floating-point value for dates with fractional seconds.
|
|
43
|
+
*
|
|
44
|
+
* # Features
|
|
45
|
+
*
|
|
46
|
+
* - Supports UTC dates with optional fractional seconds
|
|
47
|
+
* - Provides convenient constructors for common date creation patterns
|
|
48
|
+
* - Implements the `CborTagged`, `CborTaggedEncodable`, and
|
|
49
|
+
* `CborTaggedDecodable` interfaces
|
|
50
|
+
* - Supports arithmetic operations with durations and between dates
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* import { CborDate } from './date';
|
|
55
|
+
*
|
|
56
|
+
* // Create a date from a timestamp (seconds since Unix epoch)
|
|
57
|
+
* const date = CborDate.fromTimestamp(1675854714.0);
|
|
58
|
+
*
|
|
59
|
+
* // Create a date from year, month, day
|
|
60
|
+
* const date2 = CborDate.fromYmd(2023, 2, 8);
|
|
61
|
+
*
|
|
62
|
+
* // Convert to CBOR
|
|
63
|
+
* const cborValue = date.taggedCbor();
|
|
64
|
+
*
|
|
65
|
+
* // Decode from CBOR
|
|
66
|
+
* const decoded = CborDate.fromTaggedCbor(cborValue);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDecodable<CborDate> {
|
|
70
|
+
#datetime: Date;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Creates a new `CborDate` from the given JavaScript `Date`.
|
|
74
|
+
*
|
|
75
|
+
* This method creates a new `CborDate` instance by wrapping a
|
|
76
|
+
* JavaScript `Date`.
|
|
77
|
+
*
|
|
78
|
+
* @param dateTime - A `Date` instance to wrap
|
|
79
|
+
*
|
|
80
|
+
* @returns A new `CborDate` instance
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const datetime = new Date();
|
|
85
|
+
* const date = CborDate.fromDatetime(datetime);
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
static fromDatetime(dateTime: Date): CborDate {
|
|
89
|
+
const instance = new CborDate();
|
|
90
|
+
instance.#datetime = new Date(dateTime);
|
|
91
|
+
return instance;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Creates a new `CborDate` from year, month, and day components.
|
|
96
|
+
*
|
|
97
|
+
* This method creates a new `CborDate` with the time set to 00:00:00 UTC.
|
|
98
|
+
*
|
|
99
|
+
* @param year - The year component (e.g., 2023)
|
|
100
|
+
* @param month - The month component (1-12)
|
|
101
|
+
* @param day - The day component (1-31)
|
|
102
|
+
*
|
|
103
|
+
* @returns A new `CborDate` instance
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* // Create February 8, 2023
|
|
108
|
+
* const date = CborDate.fromYmd(2023, 2, 8);
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* @throws Error if the provided components do not form a valid date.
|
|
112
|
+
*/
|
|
113
|
+
static fromYmd(year: number, month: number, day: number): CborDate {
|
|
114
|
+
const dt = new Date(Date.UTC(year, month - 1, day, 0, 0, 0, 0));
|
|
115
|
+
return CborDate.fromDatetime(dt);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creates a new `CborDate` from year, month, day, hour, minute, and second
|
|
120
|
+
* components.
|
|
121
|
+
*
|
|
122
|
+
* @param year - The year component (e.g., 2023)
|
|
123
|
+
* @param month - The month component (1-12)
|
|
124
|
+
* @param day - The day component (1-31)
|
|
125
|
+
* @param hour - The hour component (0-23)
|
|
126
|
+
* @param minute - The minute component (0-59)
|
|
127
|
+
* @param second - The second component (0-59)
|
|
128
|
+
*
|
|
129
|
+
* @returns A new `CborDate` instance
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* // Create February 8, 2023, 15:30:45 UTC
|
|
134
|
+
* const date = CborDate.fromYmdHms(2023, 2, 8, 15, 30, 45);
|
|
135
|
+
* ```
|
|
136
|
+
*
|
|
137
|
+
* @throws Error if the provided components do not form a valid date and time.
|
|
138
|
+
*/
|
|
139
|
+
static fromYmdHms(
|
|
140
|
+
year: number,
|
|
141
|
+
month: number,
|
|
142
|
+
day: number,
|
|
143
|
+
hour: number,
|
|
144
|
+
minute: number,
|
|
145
|
+
second: number,
|
|
146
|
+
): CborDate {
|
|
147
|
+
const dt = new Date(Date.UTC(year, month - 1, day, hour, minute, second, 0));
|
|
148
|
+
return CborDate.fromDatetime(dt);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Creates a new `CborDate` from seconds since (or before) the Unix epoch.
|
|
153
|
+
*
|
|
154
|
+
* This method creates a new `CborDate` representing the specified number of
|
|
155
|
+
* seconds since the Unix epoch (1970-01-01T00:00:00Z). Negative values
|
|
156
|
+
* represent times before the epoch.
|
|
157
|
+
*
|
|
158
|
+
* @param secondsSinceUnixEpoch - Seconds from the Unix epoch (positive or
|
|
159
|
+
* negative), which can include a fractional part for sub-second
|
|
160
|
+
* precision
|
|
161
|
+
*
|
|
162
|
+
* @returns A new `CborDate` instance
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* // Create a date from a timestamp
|
|
167
|
+
* const date = CborDate.fromTimestamp(1675854714.0);
|
|
168
|
+
*
|
|
169
|
+
* // Create a date one second before the Unix epoch
|
|
170
|
+
* const beforeEpoch = CborDate.fromTimestamp(-1.0);
|
|
171
|
+
*
|
|
172
|
+
* // Create a date with fractional seconds
|
|
173
|
+
* const withFraction = CborDate.fromTimestamp(1675854714.5);
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
static fromTimestamp(secondsSinceUnixEpoch: number): CborDate {
|
|
177
|
+
const wholeSecondsSinceUnixEpoch = Math.trunc(secondsSinceUnixEpoch);
|
|
178
|
+
const fractionalSeconds = secondsSinceUnixEpoch - wholeSecondsSinceUnixEpoch;
|
|
179
|
+
const milliseconds = wholeSecondsSinceUnixEpoch * 1000 + fractionalSeconds * 1000;
|
|
180
|
+
return CborDate.fromDatetime(new Date(milliseconds));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Creates a new `CborDate` from a string containing an ISO-8601 (RFC-3339)
|
|
185
|
+
* date (with or without time).
|
|
186
|
+
*
|
|
187
|
+
* This method parses a string representation of a date or date-time in
|
|
188
|
+
* ISO-8601/RFC-3339 format and creates a new `CborDate` instance. It
|
|
189
|
+
* supports both full date-time strings (e.g., "2023-02-08T15:30:45Z")
|
|
190
|
+
* and date-only strings (e.g., "2023-02-08").
|
|
191
|
+
*
|
|
192
|
+
* @param value - A string containing a date or date-time in ISO-8601/RFC-3339
|
|
193
|
+
* format
|
|
194
|
+
*
|
|
195
|
+
* @returns A new `CborDate` instance if parsing succeeds
|
|
196
|
+
*
|
|
197
|
+
* @throws Error if the string cannot be parsed as a valid date or date-time
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* // Parse a date-time string
|
|
202
|
+
* const date = CborDate.fromString("2023-02-08T15:30:45Z");
|
|
203
|
+
*
|
|
204
|
+
* // Parse a date-only string (time will be set to 00:00:00)
|
|
205
|
+
* const date2 = CborDate.fromString("2023-02-08");
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
static fromString(value: string): CborDate {
|
|
209
|
+
// Try parsing as ISO 8601 date string
|
|
210
|
+
const dt = new Date(value);
|
|
211
|
+
if (isNaN(dt.getTime())) {
|
|
212
|
+
throw new CborError({ type: "InvalidDate", message: `Invalid date string: ${value}` });
|
|
213
|
+
}
|
|
214
|
+
return CborDate.fromDatetime(dt);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Creates a new `CborDate` containing the current date and time.
|
|
219
|
+
*
|
|
220
|
+
* @returns A new `CborDate` instance representing the current UTC date and time
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* const now = CborDate.now();
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
static now(): CborDate {
|
|
228
|
+
return CborDate.fromDatetime(new Date());
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Creates a new `CborDate` containing the current date and time plus the given
|
|
233
|
+
* duration.
|
|
234
|
+
*
|
|
235
|
+
* @param durationMs - The duration in milliseconds to add to the current time
|
|
236
|
+
*
|
|
237
|
+
* @returns A new `CborDate` instance representing the current UTC date and time plus
|
|
238
|
+
* the duration
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```typescript
|
|
242
|
+
* // Get a date 1 hour from now
|
|
243
|
+
* const oneHourLater = CborDate.withDurationFromNow(3600 * 1000);
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
static withDurationFromNow(durationMs: number): CborDate {
|
|
247
|
+
const now = new Date();
|
|
248
|
+
const future = new Date(now.getTime() + durationMs);
|
|
249
|
+
return CborDate.fromDatetime(future);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Returns the underlying JavaScript `Date` object.
|
|
254
|
+
*
|
|
255
|
+
* This method provides access to the wrapped JavaScript `Date`
|
|
256
|
+
* instance.
|
|
257
|
+
*
|
|
258
|
+
* @returns The wrapped `Date` instance
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```typescript
|
|
262
|
+
* const date = CborDate.now();
|
|
263
|
+
* const datetime = date.datetime();
|
|
264
|
+
* const year = datetime.getFullYear();
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
datetime(): Date {
|
|
268
|
+
return new Date(this.#datetime);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Returns the `CborDate` as the number of seconds since the Unix epoch.
|
|
273
|
+
*
|
|
274
|
+
* This method converts the date to a floating-point number representing
|
|
275
|
+
* the number of seconds since the Unix epoch (1970-01-01T00:00:00Z).
|
|
276
|
+
* Negative values represent times before the epoch. The fractional
|
|
277
|
+
* part represents sub-second precision.
|
|
278
|
+
*
|
|
279
|
+
* @returns Seconds since the Unix epoch as a `number`
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* ```typescript
|
|
283
|
+
* const date = CborDate.fromYmd(2023, 2, 8);
|
|
284
|
+
* const timestamp = date.timestamp();
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
timestamp(): number {
|
|
288
|
+
const wholeSecondsSinceUnixEpoch = Math.trunc(this.#datetime.getTime() / 1000);
|
|
289
|
+
const msecs = this.#datetime.getTime() % 1000;
|
|
290
|
+
return wholeSecondsSinceUnixEpoch + msecs / 1000.0;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Add seconds to this date.
|
|
295
|
+
*
|
|
296
|
+
* @param seconds - Seconds to add (can be fractional)
|
|
297
|
+
* @returns New CborDate instance
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```typescript
|
|
301
|
+
* const date = CborDate.fromYmd(2022, 3, 21);
|
|
302
|
+
* const tomorrow = date.add(24 * 60 * 60);
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
add(seconds: number): CborDate {
|
|
306
|
+
return CborDate.fromTimestamp(this.timestamp() + seconds);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Subtract seconds from this date.
|
|
311
|
+
*
|
|
312
|
+
* @param seconds - Seconds to subtract (can be fractional)
|
|
313
|
+
* @returns New CborDate instance
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```typescript
|
|
317
|
+
* const date = CborDate.fromYmd(2022, 3, 21);
|
|
318
|
+
* const yesterday = date.subtract(24 * 60 * 60);
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
subtract(seconds: number): CborDate {
|
|
322
|
+
return CborDate.fromTimestamp(this.timestamp() - seconds);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Get the difference in seconds between this date and another.
|
|
327
|
+
*
|
|
328
|
+
* @param other - Other CborDate to compare with
|
|
329
|
+
* @returns Difference in seconds (this - other)
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ```typescript
|
|
333
|
+
* const date1 = CborDate.fromYmd(2022, 3, 22);
|
|
334
|
+
* const date2 = CborDate.fromYmd(2022, 3, 21);
|
|
335
|
+
* const diff = date1.difference(date2);
|
|
336
|
+
* // Returns 86400 (one day in seconds)
|
|
337
|
+
* ```
|
|
338
|
+
*/
|
|
339
|
+
difference(other: CborDate): number {
|
|
340
|
+
return this.timestamp() - other.timestamp();
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Implementation of the `CborTagged` interface for `CborDate`.
|
|
345
|
+
*
|
|
346
|
+
* This implementation specifies that `CborDate` values are tagged with CBOR tag 1,
|
|
347
|
+
* which is the standard CBOR tag for date/time values represented as seconds
|
|
348
|
+
* since the Unix epoch per RFC 8949.
|
|
349
|
+
*
|
|
350
|
+
* @returns A vector containing tag 1
|
|
351
|
+
*/
|
|
352
|
+
cborTags(): Tag[] {
|
|
353
|
+
return [createTag(TAG_EPOCH_DATE_TIME, "date")];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Implementation of the `CborTaggedEncodable` interface for `CborDate`.
|
|
358
|
+
*
|
|
359
|
+
* Converts this `CborDate` to an untagged CBOR value.
|
|
360
|
+
*
|
|
361
|
+
* The date is converted to a numeric value representing the number of
|
|
362
|
+
* seconds since the Unix epoch. This value may be an integer or a
|
|
363
|
+
* floating-point number, depending on whether the date has fractional
|
|
364
|
+
* seconds.
|
|
365
|
+
*
|
|
366
|
+
* @returns A CBOR value representing the timestamp
|
|
367
|
+
*/
|
|
368
|
+
untaggedCbor(): Cbor {
|
|
369
|
+
return cbor(this.timestamp());
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Converts this `CborDate` to a tagged CBOR value with tag 1.
|
|
374
|
+
*
|
|
375
|
+
* @returns Tagged CBOR value
|
|
376
|
+
*/
|
|
377
|
+
taggedCbor(): Cbor {
|
|
378
|
+
return createTaggedCbor(this);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Implementation of the `CborTaggedDecodable` interface for `CborDate`.
|
|
383
|
+
*
|
|
384
|
+
* Creates a `CborDate` from an untagged CBOR value.
|
|
385
|
+
*
|
|
386
|
+
* The CBOR value must be a numeric value (integer or floating-point)
|
|
387
|
+
* representing the number of seconds since the Unix epoch.
|
|
388
|
+
*
|
|
389
|
+
* @param cbor - The untagged CBOR value
|
|
390
|
+
*
|
|
391
|
+
* @returns This CborDate instance (mutated)
|
|
392
|
+
*
|
|
393
|
+
* @throws Error if the CBOR value is not a valid timestamp
|
|
394
|
+
*/
|
|
395
|
+
fromUntaggedCbor(cbor: Cbor): CborDate {
|
|
396
|
+
let timestamp: number;
|
|
397
|
+
|
|
398
|
+
// Only handle numeric types (Unsigned, Negative, Float); others are invalid for dates
|
|
399
|
+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
400
|
+
switch (cbor.type) {
|
|
401
|
+
case MajorType.Unsigned:
|
|
402
|
+
timestamp = typeof cbor.value === "number" ? cbor.value : Number(cbor.value);
|
|
403
|
+
break;
|
|
404
|
+
|
|
405
|
+
case MajorType.Negative:
|
|
406
|
+
// Convert stored magnitude back to actual negative value
|
|
407
|
+
if (typeof cbor.value === "bigint") {
|
|
408
|
+
timestamp = Number(-cbor.value - 1n);
|
|
409
|
+
} else {
|
|
410
|
+
timestamp = -cbor.value - 1;
|
|
411
|
+
}
|
|
412
|
+
break;
|
|
413
|
+
|
|
414
|
+
case MajorType.Simple:
|
|
415
|
+
if (cbor.value.type === "Float") {
|
|
416
|
+
timestamp = cbor.value.value;
|
|
417
|
+
} else {
|
|
418
|
+
throw new CborError({
|
|
419
|
+
type: "Custom",
|
|
420
|
+
message: "Invalid date CBOR: expected numeric value",
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
break;
|
|
424
|
+
|
|
425
|
+
default:
|
|
426
|
+
throw new CborError({
|
|
427
|
+
type: "Custom",
|
|
428
|
+
message: "Invalid date CBOR: expected numeric value",
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const date = CborDate.fromTimestamp(timestamp);
|
|
433
|
+
this.#datetime = date.#datetime;
|
|
434
|
+
return this;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Creates a `CborDate` from a tagged CBOR value with tag 1.
|
|
439
|
+
*
|
|
440
|
+
* @param cbor - Tagged CBOR value
|
|
441
|
+
*
|
|
442
|
+
* @returns This CborDate instance (mutated)
|
|
443
|
+
*
|
|
444
|
+
* @throws Error if the CBOR value has the wrong tag or cannot be decoded
|
|
445
|
+
*/
|
|
446
|
+
fromTaggedCbor(cbor: Cbor): CborDate {
|
|
447
|
+
const expectedTags = this.cborTags();
|
|
448
|
+
validateTag(cbor, expectedTags);
|
|
449
|
+
const content = extractTaggedContent(cbor);
|
|
450
|
+
return this.fromUntaggedCbor(content);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Static method to create a CborDate from tagged CBOR.
|
|
455
|
+
*
|
|
456
|
+
* @param cbor - Tagged CBOR value
|
|
457
|
+
* @returns New CborDate instance
|
|
458
|
+
*/
|
|
459
|
+
static fromTaggedCbor(cbor: Cbor): CborDate {
|
|
460
|
+
const instance = new CborDate();
|
|
461
|
+
return instance.fromTaggedCbor(cbor);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Static method to create a CborDate from untagged CBOR.
|
|
466
|
+
*
|
|
467
|
+
* @param cbor - Untagged CBOR value
|
|
468
|
+
* @returns New CborDate instance
|
|
469
|
+
*/
|
|
470
|
+
static fromUntaggedCbor(cbor: Cbor): CborDate {
|
|
471
|
+
const instance = new CborDate();
|
|
472
|
+
return instance.fromUntaggedCbor(cbor);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Implementation of the `toString` method for `CborDate`.
|
|
477
|
+
*
|
|
478
|
+
* This implementation provides a string representation of a `CborDate` in ISO-8601
|
|
479
|
+
* format. For dates with time exactly at midnight (00:00:00), only the date
|
|
480
|
+
* part is shown. For other times, a full date-time string is shown.
|
|
481
|
+
*
|
|
482
|
+
* @returns String representation in ISO-8601 format
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* ```typescript
|
|
486
|
+
* // A date at midnight will display as just the date
|
|
487
|
+
* const date = CborDate.fromYmd(2023, 2, 8);
|
|
488
|
+
* // Returns "2023-02-08"
|
|
489
|
+
* console.log(date.toString());
|
|
490
|
+
*
|
|
491
|
+
* // A date with time will display as date and time
|
|
492
|
+
* const date2 = CborDate.fromYmdHms(2023, 2, 8, 15, 30, 45);
|
|
493
|
+
* // Returns "2023-02-08T15:30:45.000Z"
|
|
494
|
+
* console.log(date2.toString());
|
|
495
|
+
* ```
|
|
496
|
+
*/
|
|
497
|
+
toString(): string {
|
|
498
|
+
const dt = this.#datetime;
|
|
499
|
+
// Check only hours, minutes, and seconds (not milliseconds) to match Rust behavior
|
|
500
|
+
const hasTime = dt.getUTCHours() !== 0 || dt.getUTCMinutes() !== 0 || dt.getUTCSeconds() !== 0;
|
|
501
|
+
|
|
502
|
+
if (!hasTime) {
|
|
503
|
+
// Midnight (with possible subsecond precision) - show only date
|
|
504
|
+
const datePart = dt.toISOString().split("T")[0];
|
|
505
|
+
if (datePart === undefined) {
|
|
506
|
+
throw new CborError({ type: "Custom", message: "Invalid ISO string format" });
|
|
507
|
+
}
|
|
508
|
+
return datePart;
|
|
509
|
+
} else {
|
|
510
|
+
// Show full ISO datetime without milliseconds (matches Rust's SecondsFormat::Secs)
|
|
511
|
+
const iso = dt.toISOString();
|
|
512
|
+
// Remove milliseconds: "2023-02-08T15:30:45.000Z" -> "2023-02-08T15:30:45Z"
|
|
513
|
+
return iso.replace(/\.\d{3}Z$/, "Z");
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Compare two dates for equality.
|
|
519
|
+
*
|
|
520
|
+
* @param other - Other CborDate to compare
|
|
521
|
+
* @returns true if dates represent the same moment in time
|
|
522
|
+
*/
|
|
523
|
+
equals(other: CborDate): boolean {
|
|
524
|
+
return this.#datetime.getTime() === other.#datetime.getTime();
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Compare two dates.
|
|
529
|
+
*
|
|
530
|
+
* @param other - Other CborDate to compare
|
|
531
|
+
* @returns -1 if this < other, 0 if equal, 1 if this > other
|
|
532
|
+
*/
|
|
533
|
+
compare(other: CborDate): number {
|
|
534
|
+
const thisTime = this.#datetime.getTime();
|
|
535
|
+
const otherTime = other.#datetime.getTime();
|
|
536
|
+
if (thisTime < otherTime) return -1;
|
|
537
|
+
if (thisTime > otherTime) return 1;
|
|
538
|
+
return 0;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Convert to JSON (returns ISO 8601 string).
|
|
543
|
+
*
|
|
544
|
+
* @returns ISO 8601 string
|
|
545
|
+
*/
|
|
546
|
+
toJSON(): string {
|
|
547
|
+
return this.toString();
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
private constructor() {
|
|
551
|
+
this.#datetime = new Date();
|
|
552
|
+
}
|
|
553
|
+
}
|