@cratis/fundamentals 7.22.4 → 7.22.5
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/DateOnly.ts +28 -1
- package/TimeOnly.ts +51 -11
- package/TimeSpan.ts +26 -1
- package/dist/DateOnly.d.ts +1 -0
- package/dist/DateOnly.d.ts.map +1 -1
- package/dist/DateOnly.js +21 -1
- package/dist/DateOnly.js.map +1 -1
- package/dist/TimeOnly.d.ts +2 -1
- package/dist/TimeOnly.d.ts.map +1 -1
- package/dist/TimeOnly.js +30 -4
- package/dist/TimeOnly.js.map +1 -1
- package/dist/TimeSpan.d.ts.map +1 -1
- package/dist/TimeSpan.js +17 -0
- package/dist/TimeSpan.js.map +1 -1
- package/dist/cjs/DateOnly.d.ts +1 -0
- package/dist/cjs/DateOnly.d.ts.map +1 -1
- package/dist/cjs/DateOnly.js +21 -1
- package/dist/cjs/DateOnly.js.map +1 -1
- package/dist/cjs/TimeOnly.d.ts +2 -1
- package/dist/cjs/TimeOnly.d.ts.map +1 -1
- package/dist/cjs/TimeOnly.js +30 -4
- package/dist/cjs/TimeOnly.js.map +1 -1
- package/dist/cjs/TimeSpan.d.ts.map +1 -1
- package/dist/cjs/TimeSpan.js +17 -0
- package/dist/cjs/TimeSpan.js.map +1 -1
- package/dist/esm/DateOnly.d.ts +1 -0
- package/dist/esm/DateOnly.d.ts.map +1 -1
- package/dist/esm/DateOnly.js +21 -1
- package/dist/esm/DateOnly.js.map +1 -1
- package/dist/esm/TimeOnly.d.ts +2 -1
- package/dist/esm/TimeOnly.d.ts.map +1 -1
- package/dist/esm/TimeOnly.js +30 -4
- package/dist/esm/TimeOnly.js.map +1 -1
- package/dist/esm/TimeSpan.d.ts.map +1 -1
- package/dist/esm/TimeSpan.js +17 -0
- package/dist/esm/TimeSpan.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/for_DateOnly/when_parsing_an_out_of_range_calendar_date.ts +13 -0
- package/for_DateOnly/when_parsing_february_in_leap_and_common_years.ts +11 -0
- package/for_JsonSerializer/when_deserializing_a_value_map_with_out_of_range_temporal_keys.ts +19 -0
- package/for_JsonSerializer/when_deserializing_out_of_range_temporal_values.ts +20 -0
- package/for_JsonSerializer/when_round_tripping_a_value_map_with_time_only_keys_differing_below_a_millisecond.ts +20 -0
- package/for_TimeOnly/when_creating_with_out_of_range_sub_millisecond_ticks.ts +11 -0
- package/for_TimeOnly/when_parsing_an_out_of_range_time_of_day.ts +11 -0
- package/for_TimeOnly/when_parsing_the_last_moment_of_the_day.ts +10 -0
- package/for_TimeOnly/when_parsing_the_shapes_the_server_sends.ts +6 -6
- package/for_TimeOnly/when_parsing_times_that_differ_below_a_millisecond.ts +14 -0
- package/for_TimeOnly/when_rendering_a_fraction.ts +11 -0
- package/for_TimeSpan/when_parsing_out_of_range_time.ts +11 -0
- package/for_TimeSpan/when_parsing_the_largest_in_range_time_span.ts +10 -0
- package/for_TimeSpan/when_parsing_time_beyond_what_a_time_span_can_hold.ts +11 -0
- package/package.json +1 -1
package/DateOnly.ts
CHANGED
|
@@ -58,6 +58,7 @@ export class DateOnly {
|
|
|
58
58
|
* Parses the ISO-8601 calendar date the server sends, `yyyy-MM-dd`.
|
|
59
59
|
* @param value The value to parse.
|
|
60
60
|
* @returns The {@link DateOnly}.
|
|
61
|
+
* @throws {Error} If the format is invalid or a component is out of range, as C# rejects it.
|
|
61
62
|
*/
|
|
62
63
|
static parse(value: string): DateOnly {
|
|
63
64
|
const match = dateOnlyRegex.exec(value);
|
|
@@ -65,7 +66,33 @@ export class DateOnly {
|
|
|
65
66
|
throw new Error(`Invalid DateOnly format: ${value}`);
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
const year = parseInt(match[1], 10);
|
|
70
|
+
const month = parseInt(match[2], 10);
|
|
71
|
+
const day = parseInt(match[3], 10);
|
|
72
|
+
|
|
73
|
+
if (year < 1) {
|
|
74
|
+
throw new Error(`Invalid DateOnly: year ${year} is out of range 1-9999 in '${value}'`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (month < 1 || month > 12) {
|
|
78
|
+
throw new Error(`Invalid DateOnly: month ${month} is out of range 1-12 in '${value}'`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const daysInMonth = DateOnly.daysInMonth(year, month);
|
|
82
|
+
if (day < 1 || day > daysInMonth) {
|
|
83
|
+
throw new Error(`Invalid DateOnly: day ${day} is out of range 1-${daysInMonth} for ${match[1]}-${match[2]} in '${value}'`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return DateOnly.from(year, month, day);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private static daysInMonth(year: number, month: number): number {
|
|
90
|
+
if (month === 2) {
|
|
91
|
+
const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
|
92
|
+
return isLeapYear ? 29 : 28;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return [4, 6, 9, 11].includes(month) ? 30 : 31;
|
|
69
96
|
}
|
|
70
97
|
|
|
71
98
|
/**
|
package/TimeOnly.ts
CHANGED
|
@@ -40,20 +40,34 @@ export class TimeOnly {
|
|
|
40
40
|
@field(Number)
|
|
41
41
|
millisecond!: number;
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* The remaining 100 nanosecond ticks below the millisecond, 0 through 9999. Carries the last four digits of
|
|
45
|
+
* the seven-digit fraction a C# `TimeOnly` holds, so two times that differ below a millisecond stay different.
|
|
46
|
+
*/
|
|
47
|
+
@field(Number)
|
|
48
|
+
subMillisecondTicks!: number;
|
|
49
|
+
|
|
43
50
|
/**
|
|
44
51
|
* Creates a {@link TimeOnly} from its parts.
|
|
45
52
|
* @param hour The hour.
|
|
46
53
|
* @param minute The minute.
|
|
47
54
|
* @param second The second.
|
|
48
55
|
* @param millisecond The millisecond.
|
|
56
|
+
* @param subMillisecondTicks The 100 nanosecond ticks below the millisecond, 0 through 9999.
|
|
49
57
|
* @returns The {@link TimeOnly}.
|
|
58
|
+
* @throws {Error} If `subMillisecondTicks` is not a whole number from 0 through 9999.
|
|
50
59
|
*/
|
|
51
|
-
static from(hour: number, minute: number, second: number = 0, millisecond: number = 0): TimeOnly {
|
|
60
|
+
static from(hour: number, minute: number, second: number = 0, millisecond: number = 0, subMillisecondTicks: number = 0): TimeOnly {
|
|
61
|
+
if (!Number.isInteger(subMillisecondTicks) || subMillisecondTicks < 0 || subMillisecondTicks > 9999) {
|
|
62
|
+
throw new Error(`Invalid TimeOnly: subMillisecondTicks ${subMillisecondTicks} is out of range 0-9999`);
|
|
63
|
+
}
|
|
64
|
+
|
|
52
65
|
const timeOnly = new TimeOnly();
|
|
53
66
|
timeOnly.hour = hour;
|
|
54
67
|
timeOnly.minute = minute;
|
|
55
68
|
timeOnly.second = second;
|
|
56
69
|
timeOnly.millisecond = millisecond;
|
|
70
|
+
timeOnly.subMillisecondTicks = subMillisecondTicks;
|
|
57
71
|
return timeOnly;
|
|
58
72
|
}
|
|
59
73
|
|
|
@@ -62,9 +76,10 @@ export class TimeOnly {
|
|
|
62
76
|
* @param value The value to parse.
|
|
63
77
|
* @returns The {@link TimeOnly}.
|
|
64
78
|
* @remarks
|
|
65
|
-
* The seconds and the fraction are both optional because the server omits them when they are zero
|
|
66
|
-
* fraction carries up to seven digits
|
|
67
|
-
*
|
|
79
|
+
* The seconds and the fraction are both optional because the server omits them when they are zero. The
|
|
80
|
+
* fraction carries up to seven digits, all of which are kept, so C# times that differ below a millisecond
|
|
81
|
+
* stay distinct. Components outside the ranges C# accepts are rejected.
|
|
82
|
+
* @throws {Error} If the format is invalid or a component is out of range.
|
|
68
83
|
*/
|
|
69
84
|
static parse(value: string): TimeOnly {
|
|
70
85
|
const match = timeOnlyRegex.exec(value);
|
|
@@ -72,17 +87,36 @@ export class TimeOnly {
|
|
|
72
87
|
throw new Error(`Invalid TimeOnly format: ${value}`);
|
|
73
88
|
}
|
|
74
89
|
|
|
75
|
-
const
|
|
90
|
+
const hour = parseInt(match[1], 10);
|
|
91
|
+
const minute = parseInt(match[2], 10);
|
|
92
|
+
const second = match[3] ? parseInt(match[3], 10) : 0;
|
|
93
|
+
|
|
94
|
+
if (hour > 23) {
|
|
95
|
+
throw new Error(`Invalid TimeOnly: hour ${hour} is out of range 0-23 in '${value}'`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (minute > 59) {
|
|
99
|
+
throw new Error(`Invalid TimeOnly: minute ${minute} is out of range 0-59 in '${value}'`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (second > 59) {
|
|
103
|
+
throw new Error(`Invalid TimeOnly: second ${second} is out of range 0-59 in '${value}'`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const fraction = (match[4] ?? '').padEnd(7, '0');
|
|
76
107
|
|
|
77
108
|
return TimeOnly.from(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
parseInt(fraction, 10)
|
|
109
|
+
hour,
|
|
110
|
+
minute,
|
|
111
|
+
second,
|
|
112
|
+
parseInt(fraction.substring(0, 3), 10),
|
|
113
|
+
parseInt(fraction.substring(3), 10));
|
|
82
114
|
}
|
|
83
115
|
|
|
84
116
|
/**
|
|
85
|
-
* Gets the ISO-8601 representation
|
|
117
|
+
* Gets the ISO-8601 representation: `HH:mm:ss`, or `HH:mm:ss.fff` when there is a millisecond part, or the
|
|
118
|
+
* full seven-digit `HH:mm:ss.fffffff` when there is a non-zero part below the millisecond. The seven-digit form
|
|
119
|
+
* is padded, never trimmed, so the two fractional forms are the only ones produced; the parser accepts 1-7 digits.
|
|
86
120
|
* @returns The string.
|
|
87
121
|
*/
|
|
88
122
|
toString(): string {
|
|
@@ -90,6 +124,11 @@ export class TimeOnly {
|
|
|
90
124
|
const minute = this.minute.toString().padStart(2, '0');
|
|
91
125
|
const second = this.second.toString().padStart(2, '0');
|
|
92
126
|
const time = `${hour}:${minute}:${second}`;
|
|
127
|
+
const subMillisecondTicks = this.subMillisecondTicks ?? 0;
|
|
128
|
+
if (subMillisecondTicks > 0) {
|
|
129
|
+
return `${time}.${this.millisecond.toString().padStart(3, '0')}${subMillisecondTicks.toString().padStart(4, '0')}`;
|
|
130
|
+
}
|
|
131
|
+
|
|
93
132
|
return this.millisecond > 0 ? `${time}.${this.millisecond.toString().padStart(3, '0')}` : time;
|
|
94
133
|
}
|
|
95
134
|
|
|
@@ -115,6 +154,7 @@ export class TimeOnly {
|
|
|
115
154
|
this.hour === other.hour &&
|
|
116
155
|
this.minute === other.minute &&
|
|
117
156
|
this.second === other.second &&
|
|
118
|
-
this.millisecond === other.millisecond
|
|
157
|
+
this.millisecond === other.millisecond &&
|
|
158
|
+
(this.subMillisecondTicks ?? 0) === (other.subMillisecondTicks ?? 0);
|
|
119
159
|
}
|
|
120
160
|
}
|
package/TimeSpan.ts
CHANGED
|
@@ -64,7 +64,7 @@ export class TimeSpan {
|
|
|
64
64
|
* The string format should match: [-][d.]hh:mm:ss[.fffffff]
|
|
65
65
|
* @param {string} value String representation of TimeSpan.
|
|
66
66
|
* @returns {TimeSpan} A TimeSpan instance with all properties populated.
|
|
67
|
-
* @throws {Error} If the string format is invalid.
|
|
67
|
+
* @throws {Error} If the string format is invalid or hours, minutes or seconds are out of range, as C# rejects it.
|
|
68
68
|
*/
|
|
69
69
|
static parse(value: string): TimeSpan {
|
|
70
70
|
const match = timeSpanRegex.exec(value);
|
|
@@ -77,6 +77,24 @@ export class TimeSpan {
|
|
|
77
77
|
const hours = parseInt(match[3], 10);
|
|
78
78
|
const minutes = parseInt(match[4], 10);
|
|
79
79
|
const seconds = parseInt(match[5], 10);
|
|
80
|
+
|
|
81
|
+
if (hours > 23) {
|
|
82
|
+
throw new Error(`Invalid TimeSpan: hours ${hours} is out of range 0-23 in '${value}'`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (minutes > 59) {
|
|
86
|
+
throw new Error(`Invalid TimeSpan: minutes ${minutes} is out of range 0-59 in '${value}'`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (seconds > 59) {
|
|
90
|
+
throw new Error(`Invalid TimeSpan: seconds ${seconds} is out of range 0-59 in '${value}'`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const maxDays = 10675199;
|
|
94
|
+
if (days > maxDays) {
|
|
95
|
+
throw new Error(`Invalid TimeSpan: days ${days} is out of range 0-${maxDays} in '${value}'`);
|
|
96
|
+
}
|
|
97
|
+
|
|
80
98
|
const fractionalSeconds = match[6] ? match[6].padEnd(7, '0') : '0000000';
|
|
81
99
|
|
|
82
100
|
const ticksPerDay = 864000000000;
|
|
@@ -84,6 +102,13 @@ export class TimeSpan {
|
|
|
84
102
|
const ticksPerMinute = 600000000;
|
|
85
103
|
const ticksPerSecond = 10000000;
|
|
86
104
|
|
|
105
|
+
// TimeSpan.MaxValue is 10675199.02:48:05.4775807 and MinValue one tick further on the negative side.
|
|
106
|
+
const remainderTicks =
|
|
107
|
+
hours * ticksPerHour + minutes * ticksPerMinute + seconds * ticksPerSecond + parseInt(fractionalSeconds, 10);
|
|
108
|
+
if (days === maxDays && remainderTicks > (isNegative ? 100854775808 : 100854775807)) {
|
|
109
|
+
throw new Error(`Invalid TimeSpan: '${value}' is outside the range a TimeSpan can hold`);
|
|
110
|
+
}
|
|
111
|
+
|
|
87
112
|
const ticks =
|
|
88
113
|
days * ticksPerDay +
|
|
89
114
|
hours * ticksPerHour +
|
package/dist/DateOnly.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare class DateOnly {
|
|
|
6
6
|
day: number;
|
|
7
7
|
static from(year: number, month: number, day: number): DateOnly;
|
|
8
8
|
static parse(value: string): DateOnly;
|
|
9
|
+
private static daysInMonth;
|
|
9
10
|
static fromDate(date: Date): DateOnly;
|
|
10
11
|
toDate(): Date;
|
|
11
12
|
toString(): string;
|
package/dist/DateOnly.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateOnly.d.ts","sourceRoot":"","sources":["../DateOnly.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,qBAAa,QAAQ;IACjB,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,cAAc;IAMvC,IAAI,EAAG,MAAM,CAAC;IAMd,KAAK,EAAG,MAAM,CAAC;IAMf,GAAG,EAAG,MAAM,CAAC;IASb,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,CAM9D;
|
|
1
|
+
{"version":3,"file":"DateOnly.d.ts","sourceRoot":"","sources":["../DateOnly.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,qBAAa,QAAQ;IACjB,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,cAAc;IAMvC,IAAI,EAAG,MAAM,CAAC;IAMd,KAAK,EAAG,MAAM,CAAC;IAMf,GAAG,EAAG,MAAM,CAAC;IASb,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,CAM9D;IAQD,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAwBpC;IAED,OAAO,CAAC,MAAM,CAAC,WAAW;IAiB1B,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAEpC;IASD,MAAM,IAAI,IAAI,CAEb;IAMD,QAAQ,IAAI,MAAM,CAIjB;IASD,MAAM,IAAI,MAAM,CAEf;IAOD,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAElD;CACJ"}
|
package/dist/DateOnly.js
CHANGED
|
@@ -19,7 +19,27 @@ export class DateOnly {
|
|
|
19
19
|
if (match === null) {
|
|
20
20
|
throw new Error(`Invalid DateOnly format: ${value}`);
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
const year = parseInt(match[1], 10);
|
|
23
|
+
const month = parseInt(match[2], 10);
|
|
24
|
+
const day = parseInt(match[3], 10);
|
|
25
|
+
if (year < 1) {
|
|
26
|
+
throw new Error(`Invalid DateOnly: year ${year} is out of range 1-9999 in '${value}'`);
|
|
27
|
+
}
|
|
28
|
+
if (month < 1 || month > 12) {
|
|
29
|
+
throw new Error(`Invalid DateOnly: month ${month} is out of range 1-12 in '${value}'`);
|
|
30
|
+
}
|
|
31
|
+
const daysInMonth = DateOnly.daysInMonth(year, month);
|
|
32
|
+
if (day < 1 || day > daysInMonth) {
|
|
33
|
+
throw new Error(`Invalid DateOnly: day ${day} is out of range 1-${daysInMonth} for ${match[1]}-${match[2]} in '${value}'`);
|
|
34
|
+
}
|
|
35
|
+
return DateOnly.from(year, month, day);
|
|
36
|
+
}
|
|
37
|
+
static daysInMonth(year, month) {
|
|
38
|
+
if (month === 2) {
|
|
39
|
+
const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
|
40
|
+
return isLeapYear ? 29 : 28;
|
|
41
|
+
}
|
|
42
|
+
return [4, 6, 9, 11].includes(month) ? 30 : 31;
|
|
23
43
|
}
|
|
24
44
|
static fromDate(date) {
|
|
25
45
|
return DateOnly.from(date.getFullYear(), date.getMonth() + 1, date.getDate());
|
package/dist/DateOnly.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateOnly.js","sourceRoot":"","sources":["../DateOnly.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,aAAa,GAAG,2BAA2B,CAAC;AAclD,MAAM,OAAO,QAAQ;IACjB,MAAM,CAAU,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC;IAMvC,IAAI,CAAU;IAMd,KAAK,CAAU;IAMf,GAAG,CAAU;IASb,MAAM,CAAC,IAAI,CAAC,IAAY,EAAE,KAAa,EAAE,GAAW;QAChD,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;QAChC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC;QACrB,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;QACvB,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC;QACnB,OAAO,QAAQ,CAAC;IACpB,CAAC;
|
|
1
|
+
{"version":3,"file":"DateOnly.js","sourceRoot":"","sources":["../DateOnly.ts"],"names":[],"mappings":"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"}
|
package/dist/TimeOnly.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ export declare class TimeOnly {
|
|
|
5
5
|
minute: number;
|
|
6
6
|
second: number;
|
|
7
7
|
millisecond: number;
|
|
8
|
-
|
|
8
|
+
subMillisecondTicks: number;
|
|
9
|
+
static from(hour: number, minute: number, second?: number, millisecond?: number, subMillisecondTicks?: number): TimeOnly;
|
|
9
10
|
static parse(value: string): TimeOnly;
|
|
10
11
|
toString(): string;
|
|
11
12
|
toJSON(): string;
|
package/dist/TimeOnly.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeOnly.d.ts","sourceRoot":"","sources":["../TimeOnly.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,qBAAa,QAAQ;IACjB,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,cAAc;IAMvC,IAAI,EAAG,MAAM,CAAC;IAMd,MAAM,EAAG,MAAM,CAAC;IAMhB,MAAM,EAAG,MAAM,CAAC;IAMhB,WAAW,EAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"TimeOnly.d.ts","sourceRoot":"","sources":["../TimeOnly.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,qBAAa,QAAQ;IACjB,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,cAAc;IAMvC,IAAI,EAAG,MAAM,CAAC;IAMd,MAAM,EAAG,MAAM,CAAC;IAMhB,MAAM,EAAG,MAAM,CAAC;IAMhB,WAAW,EAAG,MAAM,CAAC;IAOrB,mBAAmB,EAAG,MAAM,CAAC;IAY7B,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,MAAU,EAAE,WAAW,GAAE,MAAU,EAAE,mBAAmB,GAAE,MAAU,GAAG,QAAQ,CAYhI;IAYD,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CA8BpC;IAQD,QAAQ,IAAI,MAAM,CAWjB;IAUD,MAAM,IAAI,MAAM,CAEf;IAOD,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAOlD;CACJ"}
|
package/dist/TimeOnly.js
CHANGED
|
@@ -8,12 +8,17 @@ export class TimeOnly {
|
|
|
8
8
|
minute;
|
|
9
9
|
second;
|
|
10
10
|
millisecond;
|
|
11
|
-
|
|
11
|
+
subMillisecondTicks;
|
|
12
|
+
static from(hour, minute, second = 0, millisecond = 0, subMillisecondTicks = 0) {
|
|
13
|
+
if (!Number.isInteger(subMillisecondTicks) || subMillisecondTicks < 0 || subMillisecondTicks > 9999) {
|
|
14
|
+
throw new Error(`Invalid TimeOnly: subMillisecondTicks ${subMillisecondTicks} is out of range 0-9999`);
|
|
15
|
+
}
|
|
12
16
|
const timeOnly = new TimeOnly();
|
|
13
17
|
timeOnly.hour = hour;
|
|
14
18
|
timeOnly.minute = minute;
|
|
15
19
|
timeOnly.second = second;
|
|
16
20
|
timeOnly.millisecond = millisecond;
|
|
21
|
+
timeOnly.subMillisecondTicks = subMillisecondTicks;
|
|
17
22
|
return timeOnly;
|
|
18
23
|
}
|
|
19
24
|
static parse(value) {
|
|
@@ -21,14 +26,30 @@ export class TimeOnly {
|
|
|
21
26
|
if (match === null) {
|
|
22
27
|
throw new Error(`Invalid TimeOnly format: ${value}`);
|
|
23
28
|
}
|
|
24
|
-
const
|
|
25
|
-
|
|
29
|
+
const hour = parseInt(match[1], 10);
|
|
30
|
+
const minute = parseInt(match[2], 10);
|
|
31
|
+
const second = match[3] ? parseInt(match[3], 10) : 0;
|
|
32
|
+
if (hour > 23) {
|
|
33
|
+
throw new Error(`Invalid TimeOnly: hour ${hour} is out of range 0-23 in '${value}'`);
|
|
34
|
+
}
|
|
35
|
+
if (minute > 59) {
|
|
36
|
+
throw new Error(`Invalid TimeOnly: minute ${minute} is out of range 0-59 in '${value}'`);
|
|
37
|
+
}
|
|
38
|
+
if (second > 59) {
|
|
39
|
+
throw new Error(`Invalid TimeOnly: second ${second} is out of range 0-59 in '${value}'`);
|
|
40
|
+
}
|
|
41
|
+
const fraction = (match[4] ?? '').padEnd(7, '0');
|
|
42
|
+
return TimeOnly.from(hour, minute, second, parseInt(fraction.substring(0, 3), 10), parseInt(fraction.substring(3), 10));
|
|
26
43
|
}
|
|
27
44
|
toString() {
|
|
28
45
|
const hour = this.hour.toString().padStart(2, '0');
|
|
29
46
|
const minute = this.minute.toString().padStart(2, '0');
|
|
30
47
|
const second = this.second.toString().padStart(2, '0');
|
|
31
48
|
const time = `${hour}:${minute}:${second}`;
|
|
49
|
+
const subMillisecondTicks = this.subMillisecondTicks ?? 0;
|
|
50
|
+
if (subMillisecondTicks > 0) {
|
|
51
|
+
return `${time}.${this.millisecond.toString().padStart(3, '0')}${subMillisecondTicks.toString().padStart(4, '0')}`;
|
|
52
|
+
}
|
|
32
53
|
return this.millisecond > 0 ? `${time}.${this.millisecond.toString().padStart(3, '0')}` : time;
|
|
33
54
|
}
|
|
34
55
|
toJSON() {
|
|
@@ -39,7 +60,8 @@ export class TimeOnly {
|
|
|
39
60
|
this.hour === other.hour &&
|
|
40
61
|
this.minute === other.minute &&
|
|
41
62
|
this.second === other.second &&
|
|
42
|
-
this.millisecond === other.millisecond
|
|
63
|
+
this.millisecond === other.millisecond &&
|
|
64
|
+
(this.subMillisecondTicks ?? 0) === (other.subMillisecondTicks ?? 0);
|
|
43
65
|
}
|
|
44
66
|
}
|
|
45
67
|
__decorate([
|
|
@@ -58,4 +80,8 @@ __decorate([
|
|
|
58
80
|
field(Number),
|
|
59
81
|
__metadata("design:type", Number)
|
|
60
82
|
], TimeOnly.prototype, "millisecond", void 0);
|
|
83
|
+
__decorate([
|
|
84
|
+
field(Number),
|
|
85
|
+
__metadata("design:type", Number)
|
|
86
|
+
], TimeOnly.prototype, "subMillisecondTicks", void 0);
|
|
61
87
|
//# sourceMappingURL=TimeOnly.js.map
|
package/dist/TimeOnly.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeOnly.js","sourceRoot":"","sources":["../TimeOnly.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,aAAa,GAAG,gDAAgD,CAAC;AASvE,MAAM,OAAO,QAAQ;IACjB,MAAM,CAAU,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC;IAMvC,IAAI,CAAU;IAMd,MAAM,CAAU;IAMhB,MAAM,CAAU;IAMhB,WAAW,CAAU;
|
|
1
|
+
{"version":3,"file":"TimeOnly.js","sourceRoot":"","sources":["../TimeOnly.ts"],"names":[],"mappings":"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"}
|
package/dist/TimeSpan.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeSpan.d.ts","sourceRoot":"","sources":["../TimeSpan.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,qBAAa,QAAQ;IACjB,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,cAAc;IAIvC,KAAK,EAAG,MAAM,CAAC;IAGf,IAAI,EAAG,MAAM,CAAC;IAGd,KAAK,EAAG,MAAM,CAAC;IAGf,YAAY,EAAG,MAAM,CAAC;IAGtB,YAAY,EAAG,MAAM,CAAC;IAGtB,WAAW,EAAG,MAAM,CAAC;IAGrB,OAAO,EAAG,MAAM,CAAC;IAGjB,OAAO,EAAG,MAAM,CAAC;IAGjB,SAAS,EAAG,MAAM,CAAC;IAGnB,UAAU,EAAG,MAAM,CAAC;IAGpB,iBAAiB,EAAG,MAAM,CAAC;IAG3B,iBAAiB,EAAG,MAAM,CAAC;IAG3B,gBAAgB,EAAG,MAAM,CAAC;IAG1B,YAAY,EAAG,MAAM,CAAC;IAGtB,YAAY,EAAG,MAAM,CAAC;IAStB,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"TimeSpan.d.ts","sourceRoot":"","sources":["../TimeSpan.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,qBAAa,QAAQ;IACjB,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,cAAc;IAIvC,KAAK,EAAG,MAAM,CAAC;IAGf,IAAI,EAAG,MAAM,CAAC;IAGd,KAAK,EAAG,MAAM,CAAC;IAGf,YAAY,EAAG,MAAM,CAAC;IAGtB,YAAY,EAAG,MAAM,CAAC;IAGtB,WAAW,EAAG,MAAM,CAAC;IAGrB,OAAO,EAAG,MAAM,CAAC;IAGjB,OAAO,EAAG,MAAM,CAAC;IAGjB,SAAS,EAAG,MAAM,CAAC;IAGnB,UAAU,EAAG,MAAM,CAAC;IAGpB,iBAAiB,EAAG,MAAM,CAAC;IAG3B,iBAAiB,EAAG,MAAM,CAAC;IAG3B,gBAAgB,EAAG,MAAM,CAAC;IAG1B,YAAY,EAAG,MAAM,CAAC;IAGtB,YAAY,EAAG,MAAM,CAAC;IAStB,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAsEpC;IAOD,QAAQ,IAAI,MAAM,CAmCjB;IAOD,MAAM,IAAI,MAAM,CAEf;CACJ"}
|
package/dist/TimeSpan.js
CHANGED
|
@@ -29,11 +29,28 @@ export class TimeSpan {
|
|
|
29
29
|
const hours = parseInt(match[3], 10);
|
|
30
30
|
const minutes = parseInt(match[4], 10);
|
|
31
31
|
const seconds = parseInt(match[5], 10);
|
|
32
|
+
if (hours > 23) {
|
|
33
|
+
throw new Error(`Invalid TimeSpan: hours ${hours} is out of range 0-23 in '${value}'`);
|
|
34
|
+
}
|
|
35
|
+
if (minutes > 59) {
|
|
36
|
+
throw new Error(`Invalid TimeSpan: minutes ${minutes} is out of range 0-59 in '${value}'`);
|
|
37
|
+
}
|
|
38
|
+
if (seconds > 59) {
|
|
39
|
+
throw new Error(`Invalid TimeSpan: seconds ${seconds} is out of range 0-59 in '${value}'`);
|
|
40
|
+
}
|
|
41
|
+
const maxDays = 10675199;
|
|
42
|
+
if (days > maxDays) {
|
|
43
|
+
throw new Error(`Invalid TimeSpan: days ${days} is out of range 0-${maxDays} in '${value}'`);
|
|
44
|
+
}
|
|
32
45
|
const fractionalSeconds = match[6] ? match[6].padEnd(7, '0') : '0000000';
|
|
33
46
|
const ticksPerDay = 864000000000;
|
|
34
47
|
const ticksPerHour = 36000000000;
|
|
35
48
|
const ticksPerMinute = 600000000;
|
|
36
49
|
const ticksPerSecond = 10000000;
|
|
50
|
+
const remainderTicks = hours * ticksPerHour + minutes * ticksPerMinute + seconds * ticksPerSecond + parseInt(fractionalSeconds, 10);
|
|
51
|
+
if (days === maxDays && remainderTicks > (isNegative ? 100854775808 : 100854775807)) {
|
|
52
|
+
throw new Error(`Invalid TimeSpan: '${value}' is outside the range a TimeSpan can hold`);
|
|
53
|
+
}
|
|
37
54
|
const ticks = days * ticksPerDay +
|
|
38
55
|
hours * ticksPerHour +
|
|
39
56
|
minutes * ticksPerMinute +
|
package/dist/TimeSpan.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeSpan.js","sourceRoot":"","sources":["../TimeSpan.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,MAAM,aAAa,GAAG,6DAA6D,CAAC;AAKpF,MAAM,OAAO,QAAQ;IACjB,MAAM,CAAU,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC;IAIvC,KAAK,CAAU;IAGf,IAAI,CAAU;IAGd,KAAK,CAAU;IAGf,YAAY,CAAU;IAGtB,YAAY,CAAU;IAGtB,WAAW,CAAU;IAGrB,OAAO,CAAU;IAGjB,OAAO,CAAU;IAGjB,SAAS,CAAU;IAGnB,UAAU,CAAU;IAGpB,iBAAiB,CAAU;IAG3B,iBAAiB,CAAU;IAG3B,gBAAgB,CAAU;IAG1B,YAAY,CAAU;IAGtB,YAAY,CAAU;IAStB,MAAM,CAAC,KAAK,CAAC,KAAa;QACtB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,EAAE,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;QACpC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"TimeSpan.js","sourceRoot":"","sources":["../TimeSpan.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/DateOnly.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare class DateOnly {
|
|
|
6
6
|
day: number;
|
|
7
7
|
static from(year: number, month: number, day: number): DateOnly;
|
|
8
8
|
static parse(value: string): DateOnly;
|
|
9
|
+
private static daysInMonth;
|
|
9
10
|
static fromDate(date: Date): DateOnly;
|
|
10
11
|
toDate(): Date;
|
|
11
12
|
toString(): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateOnly.d.ts","sourceRoot":"","sources":["../../DateOnly.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,qBAAa,QAAQ;IACjB,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,cAAc;IAMvC,IAAI,EAAG,MAAM,CAAC;IAMd,KAAK,EAAG,MAAM,CAAC;IAMf,GAAG,EAAG,MAAM,CAAC;IASb,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ;
|
|
1
|
+
{"version":3,"file":"DateOnly.d.ts","sourceRoot":"","sources":["../../DateOnly.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,qBAAa,QAAQ;IACjB,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,cAAc;IAMvC,IAAI,EAAG,MAAM,CAAC;IAMd,KAAK,EAAG,MAAM,CAAC;IAMf,GAAG,EAAG,MAAM,CAAC;IASb,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ;IAc/D,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ;IA0BrC,OAAO,CAAC,MAAM,CAAC,WAAW;IAiB1B,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ;IAWrC,MAAM,IAAI,IAAI;IAQd,QAAQ,IAAI,MAAM;IAalB,MAAM,IAAI,MAAM;IAShB,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO;CAGtD"}
|
package/dist/cjs/DateOnly.js
CHANGED
|
@@ -22,7 +22,27 @@ class DateOnly {
|
|
|
22
22
|
if (match === null) {
|
|
23
23
|
throw new Error(`Invalid DateOnly format: ${value}`);
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
const year = parseInt(match[1], 10);
|
|
26
|
+
const month = parseInt(match[2], 10);
|
|
27
|
+
const day = parseInt(match[3], 10);
|
|
28
|
+
if (year < 1) {
|
|
29
|
+
throw new Error(`Invalid DateOnly: year ${year} is out of range 1-9999 in '${value}'`);
|
|
30
|
+
}
|
|
31
|
+
if (month < 1 || month > 12) {
|
|
32
|
+
throw new Error(`Invalid DateOnly: month ${month} is out of range 1-12 in '${value}'`);
|
|
33
|
+
}
|
|
34
|
+
const daysInMonth = DateOnly.daysInMonth(year, month);
|
|
35
|
+
if (day < 1 || day > daysInMonth) {
|
|
36
|
+
throw new Error(`Invalid DateOnly: day ${day} is out of range 1-${daysInMonth} for ${match[1]}-${match[2]} in '${value}'`);
|
|
37
|
+
}
|
|
38
|
+
return DateOnly.from(year, month, day);
|
|
39
|
+
}
|
|
40
|
+
static daysInMonth(year, month) {
|
|
41
|
+
if (month === 2) {
|
|
42
|
+
const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
|
43
|
+
return isLeapYear ? 29 : 28;
|
|
44
|
+
}
|
|
45
|
+
return [4, 6, 9, 11].includes(month) ? 30 : 31;
|
|
26
46
|
}
|
|
27
47
|
static fromDate(date) {
|
|
28
48
|
return DateOnly.from(date.getFullYear(), date.getMonth() + 1, date.getDate());
|
package/dist/cjs/DateOnly.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateOnly.js","sources":["../../DateOnly.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { field } from './fieldDecorator';\nimport { typeKey } from './typeKey';\n\nconst dateOnlyRegex = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/**\n * Represents a date with no time and no time zone - a day on a calendar.\n * @remarks\n * Deliberately not a JavaScript `Date`. A `Date` is an instant, and a calendar date is not one: turning\n * `2026-05-12` into a `Date` produces UTC midnight, which every browser-local getter west of UTC reads back as\n * the 11th. That is a wrong answer that looks right, and it is only wrong for users in some time zones - which is\n * how it survives development in others.\n *\n * Holding the three parts the server sent means there is no instant to convert and nothing to shift. Where a\n * `Date` is genuinely wanted - to feed a date picker, or to do arithmetic - {@link toDate} constructs one in the\n * local time zone, and the choice is then visible at the call site making it.\n */\nexport class DateOnly {\n static readonly [typeKey] = 'DateOnly';\n\n /**\n * The year.\n */\n @field(Number)\n year!: number;\n\n /**\n * The month, 1 through 12.\n */\n @field(Number)\n month!: number;\n\n /**\n * The day of the month, 1 through 31.\n */\n @field(Number)\n day!: number;\n\n /**\n * Creates a {@link DateOnly} from its parts.\n * @param year The year.\n * @param month The month, 1 through 12.\n * @param day The day of the month.\n * @returns The {@link DateOnly}.\n */\n static from(year: number, month: number, day: number): DateOnly {\n const dateOnly = new DateOnly();\n dateOnly.year = year;\n dateOnly.month = month;\n dateOnly.day = day;\n return dateOnly;\n }\n\n /**\n * Parses the ISO-8601 calendar date the server sends, `yyyy-MM-dd`.\n * @param value The value to parse.\n * @returns The {@link DateOnly}.\n */\n static parse(value: string): DateOnly {\n const match = dateOnlyRegex.exec(value);\n if (match === null) {\n throw new Error(`Invalid DateOnly format: ${value}`);\n }\n\n
|
|
1
|
+
{"version":3,"file":"DateOnly.js","sources":["../../DateOnly.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { field } from './fieldDecorator';\nimport { typeKey } from './typeKey';\n\nconst dateOnlyRegex = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/**\n * Represents a date with no time and no time zone - a day on a calendar.\n * @remarks\n * Deliberately not a JavaScript `Date`. A `Date` is an instant, and a calendar date is not one: turning\n * `2026-05-12` into a `Date` produces UTC midnight, which every browser-local getter west of UTC reads back as\n * the 11th. That is a wrong answer that looks right, and it is only wrong for users in some time zones - which is\n * how it survives development in others.\n *\n * Holding the three parts the server sent means there is no instant to convert and nothing to shift. Where a\n * `Date` is genuinely wanted - to feed a date picker, or to do arithmetic - {@link toDate} constructs one in the\n * local time zone, and the choice is then visible at the call site making it.\n */\nexport class DateOnly {\n static readonly [typeKey] = 'DateOnly';\n\n /**\n * The year.\n */\n @field(Number)\n year!: number;\n\n /**\n * The month, 1 through 12.\n */\n @field(Number)\n month!: number;\n\n /**\n * The day of the month, 1 through 31.\n */\n @field(Number)\n day!: number;\n\n /**\n * Creates a {@link DateOnly} from its parts.\n * @param year The year.\n * @param month The month, 1 through 12.\n * @param day The day of the month.\n * @returns The {@link DateOnly}.\n */\n static from(year: number, month: number, day: number): DateOnly {\n const dateOnly = new DateOnly();\n dateOnly.year = year;\n dateOnly.month = month;\n dateOnly.day = day;\n return dateOnly;\n }\n\n /**\n * Parses the ISO-8601 calendar date the server sends, `yyyy-MM-dd`.\n * @param value The value to parse.\n * @returns The {@link DateOnly}.\n * @throws {Error} If the format is invalid or a component is out of range, as C# rejects it.\n */\n static parse(value: string): DateOnly {\n const match = dateOnlyRegex.exec(value);\n if (match === null) {\n throw new Error(`Invalid DateOnly format: ${value}`);\n }\n\n const year = parseInt(match[1], 10);\n const month = parseInt(match[2], 10);\n const day = parseInt(match[3], 10);\n\n if (year < 1) {\n throw new Error(`Invalid DateOnly: year ${year} is out of range 1-9999 in '${value}'`);\n }\n\n if (month < 1 || month > 12) {\n throw new Error(`Invalid DateOnly: month ${month} is out of range 1-12 in '${value}'`);\n }\n\n const daysInMonth = DateOnly.daysInMonth(year, month);\n if (day < 1 || day > daysInMonth) {\n throw new Error(`Invalid DateOnly: day ${day} is out of range 1-${daysInMonth} for ${match[1]}-${match[2]} in '${value}'`);\n }\n\n return DateOnly.from(year, month, day);\n }\n\n private static daysInMonth(year: number, month: number): number {\n if (month === 2) {\n const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n return isLeapYear ? 29 : 28;\n }\n\n return [4, 6, 9, 11].includes(month) ? 30 : 31;\n }\n\n /**\n * Creates a {@link DateOnly} for the calendar date a {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date | Date} falls on in the local time zone.\n * @param date The date to take the calendar date of.\n * @returns The {@link DateOnly}.\n * @remarks\n * Reads the local parts rather than the UTC ones, because the calendar date a moment falls on is a question\n * only a time zone can answer, and the local one is the one the person looking at the screen is in.\n */\n static fromDate(date: Date): DateOnly {\n return DateOnly.from(date.getFullYear(), date.getMonth() + 1, date.getDate());\n }\n\n /**\n * Converts to a {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date | Date} at midnight in the local time zone.\n * @returns The {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date | Date}.\n * @remarks\n * Local rather than UTC, so the date a caller reads back with `getDate()` is the one they started with. This\n * invents a time that was never sent, which is why it is a method to call rather than what the value is.\n */\n toDate(): Date {\n return new Date(this.year, this.month - 1, this.day);\n }\n\n /**\n * Gets the ISO-8601 representation, `yyyy-MM-dd` - the same form the server sent.\n * @returns The string.\n */\n toString(): string {\n const month = this.month.toString().padStart(2, '0');\n const day = this.day.toString().padStart(2, '0');\n return `${this.year.toString().padStart(4, '0')}-${month}-${day}`;\n }\n\n /**\n * Gets the ISO-8601 representation used when this is serialized as JSON.\n *\n * Without this, `JSON.stringify` falls back to enumerating `year`, `month` and `day`, so a\n * request body carries a component object where the server expects the scalar string.\n * @returns The string.\n */\n toJSON(): string {\n return this.toString();\n }\n\n /**\n * Determines whether this is the same calendar date as another.\n * @param other The other date.\n * @returns True when they are the same date.\n */\n equals(other: DateOnly | undefined | null): boolean {\n return !!other && this.year === other.year && this.month === other.month && this.day === other.day;\n }\n}\n"],"names":["typeKey","__decorate","field"],"mappings":"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"}
|
package/dist/cjs/TimeOnly.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ export declare class TimeOnly {
|
|
|
5
5
|
minute: number;
|
|
6
6
|
second: number;
|
|
7
7
|
millisecond: number;
|
|
8
|
-
|
|
8
|
+
subMillisecondTicks: number;
|
|
9
|
+
static from(hour: number, minute: number, second?: number, millisecond?: number, subMillisecondTicks?: number): TimeOnly;
|
|
9
10
|
static parse(value: string): TimeOnly;
|
|
10
11
|
toString(): string;
|
|
11
12
|
toJSON(): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeOnly.d.ts","sourceRoot":"","sources":["../../TimeOnly.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,qBAAa,QAAQ;IACjB,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,cAAc;IAMvC,IAAI,EAAG,MAAM,CAAC;IAMd,MAAM,EAAG,MAAM,CAAC;IAMhB,MAAM,EAAG,MAAM,CAAC;IAMhB,WAAW,EAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"TimeOnly.d.ts","sourceRoot":"","sources":["../../TimeOnly.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,qBAAa,QAAQ;IACjB,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,cAAc;IAMvC,IAAI,EAAG,MAAM,CAAC;IAMd,MAAM,EAAG,MAAM,CAAC;IAMhB,MAAM,EAAG,MAAM,CAAC;IAMhB,WAAW,EAAG,MAAM,CAAC;IAOrB,mBAAmB,EAAG,MAAM,CAAC;IAY7B,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,MAAU,EAAE,WAAW,GAAE,MAAU,EAAE,mBAAmB,GAAE,MAAU,GAAG,QAAQ;IAwBjI,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ;IAsCrC,QAAQ,IAAI,MAAM;IAqBlB,MAAM,IAAI,MAAM;IAShB,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO;CAQtD"}
|
package/dist/cjs/TimeOnly.js
CHANGED
|
@@ -11,12 +11,17 @@ class TimeOnly {
|
|
|
11
11
|
minute;
|
|
12
12
|
second;
|
|
13
13
|
millisecond;
|
|
14
|
-
|
|
14
|
+
subMillisecondTicks;
|
|
15
|
+
static from(hour, minute, second = 0, millisecond = 0, subMillisecondTicks = 0) {
|
|
16
|
+
if (!Number.isInteger(subMillisecondTicks) || subMillisecondTicks < 0 || subMillisecondTicks > 9999) {
|
|
17
|
+
throw new Error(`Invalid TimeOnly: subMillisecondTicks ${subMillisecondTicks} is out of range 0-9999`);
|
|
18
|
+
}
|
|
15
19
|
const timeOnly = new TimeOnly();
|
|
16
20
|
timeOnly.hour = hour;
|
|
17
21
|
timeOnly.minute = minute;
|
|
18
22
|
timeOnly.second = second;
|
|
19
23
|
timeOnly.millisecond = millisecond;
|
|
24
|
+
timeOnly.subMillisecondTicks = subMillisecondTicks;
|
|
20
25
|
return timeOnly;
|
|
21
26
|
}
|
|
22
27
|
static parse(value) {
|
|
@@ -24,14 +29,30 @@ class TimeOnly {
|
|
|
24
29
|
if (match === null) {
|
|
25
30
|
throw new Error(`Invalid TimeOnly format: ${value}`);
|
|
26
31
|
}
|
|
27
|
-
const
|
|
28
|
-
|
|
32
|
+
const hour = parseInt(match[1], 10);
|
|
33
|
+
const minute = parseInt(match[2], 10);
|
|
34
|
+
const second = match[3] ? parseInt(match[3], 10) : 0;
|
|
35
|
+
if (hour > 23) {
|
|
36
|
+
throw new Error(`Invalid TimeOnly: hour ${hour} is out of range 0-23 in '${value}'`);
|
|
37
|
+
}
|
|
38
|
+
if (minute > 59) {
|
|
39
|
+
throw new Error(`Invalid TimeOnly: minute ${minute} is out of range 0-59 in '${value}'`);
|
|
40
|
+
}
|
|
41
|
+
if (second > 59) {
|
|
42
|
+
throw new Error(`Invalid TimeOnly: second ${second} is out of range 0-59 in '${value}'`);
|
|
43
|
+
}
|
|
44
|
+
const fraction = (match[4] ?? '').padEnd(7, '0');
|
|
45
|
+
return TimeOnly.from(hour, minute, second, parseInt(fraction.substring(0, 3), 10), parseInt(fraction.substring(3), 10));
|
|
29
46
|
}
|
|
30
47
|
toString() {
|
|
31
48
|
const hour = this.hour.toString().padStart(2, '0');
|
|
32
49
|
const minute = this.minute.toString().padStart(2, '0');
|
|
33
50
|
const second = this.second.toString().padStart(2, '0');
|
|
34
51
|
const time = `${hour}:${minute}:${second}`;
|
|
52
|
+
const subMillisecondTicks = this.subMillisecondTicks ?? 0;
|
|
53
|
+
if (subMillisecondTicks > 0) {
|
|
54
|
+
return `${time}.${this.millisecond.toString().padStart(3, '0')}${subMillisecondTicks.toString().padStart(4, '0')}`;
|
|
55
|
+
}
|
|
35
56
|
return this.millisecond > 0 ? `${time}.${this.millisecond.toString().padStart(3, '0')}` : time;
|
|
36
57
|
}
|
|
37
58
|
toJSON() {
|
|
@@ -42,7 +63,8 @@ class TimeOnly {
|
|
|
42
63
|
this.hour === other.hour &&
|
|
43
64
|
this.minute === other.minute &&
|
|
44
65
|
this.second === other.second &&
|
|
45
|
-
this.millisecond === other.millisecond
|
|
66
|
+
this.millisecond === other.millisecond &&
|
|
67
|
+
(this.subMillisecondTicks ?? 0) === (other.subMillisecondTicks ?? 0);
|
|
46
68
|
}
|
|
47
69
|
}
|
|
48
70
|
_tslib.__decorate([
|
|
@@ -61,6 +83,10 @@ _tslib.__decorate([
|
|
|
61
83
|
fieldDecorator.field(Number),
|
|
62
84
|
_tslib.__metadata("design:type", Number)
|
|
63
85
|
], TimeOnly.prototype, "millisecond", void 0);
|
|
86
|
+
_tslib.__decorate([
|
|
87
|
+
fieldDecorator.field(Number),
|
|
88
|
+
_tslib.__metadata("design:type", Number)
|
|
89
|
+
], TimeOnly.prototype, "subMillisecondTicks", void 0);
|
|
64
90
|
|
|
65
91
|
exports.TimeOnly = TimeOnly;
|
|
66
92
|
//# sourceMappingURL=TimeOnly.js.map
|