@nextera.one/tps-standard 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +40 -3
- package/dist/date.d.ts +5 -5
- package/dist/date.js +5 -1
- package/dist/date.js.map +1 -1
- package/dist/drivers/tps.d.ts +8 -17
- package/dist/drivers/tps.js +64 -84
- package/dist/drivers/tps.js.map +1 -1
- package/dist/esm/date.js +6 -2
- package/dist/esm/date.js.map +1 -1
- package/dist/esm/drivers/tps.js +64 -84
- package/dist/esm/drivers/tps.js.map +1 -1
- package/dist/esm/index.js +152 -14
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/uid.js +3 -0
- package/dist/esm/uid.js.map +1 -1
- package/dist/esm/utils/tps-native.js +249 -0
- package/dist/esm/utils/tps-native.js.map +1 -0
- package/dist/esm/utils/tps-string.js +58 -15
- package/dist/esm/utils/tps-string.js.map +1 -1
- package/dist/index.d.ts +25 -6
- package/dist/index.js +152 -14
- package/dist/index.js.map +1 -1
- package/dist/tps.min.js +3786 -0
- package/dist/types.d.ts +11 -0
- package/dist/uid.js +3 -0
- package/dist/uid.js.map +1 -1
- package/dist/utils/tps-native.d.ts +32 -0
- package/dist/utils/tps-native.js +265 -0
- package/dist/utils/tps-native.js.map +1 -0
- package/dist/utils/tps-string.d.ts +2 -2
- package/dist/utils/tps-string.js +57 -14
- package/dist/utils/tps-string.js.map +1 -1
- package/package.json +3 -2
- package/src/date.ts +14 -4
- package/src/drivers/tps.ts +83 -104
- package/src/index.ts +213 -15
- package/src/types.ts +13 -0
- package/src/uid.ts +3 -0
- package/src/utils/tps-native.ts +346 -0
- package/src/utils/tps-string.ts +82 -15
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { TPSComponents } from "../types";
|
|
2
|
+
|
|
3
|
+
export const TPS_DAY_MS = 24 * 60 * 60 * 1000;
|
|
4
|
+
export const TPS_DAY_START_OFFSET_MS = 7 * 60 * 60 * 1000;
|
|
5
|
+
export const TPS_DAYS_PER_WEEK = 7;
|
|
6
|
+
export const TPS_WEEKS_PER_MONTH = 4;
|
|
7
|
+
export const TPS_MONTHS_PER_YEAR = 12;
|
|
8
|
+
export const TPS_DAYS_PER_MONTH =
|
|
9
|
+
TPS_DAYS_PER_WEEK * TPS_WEEKS_PER_MONTH;
|
|
10
|
+
export const TPS_DAYS_PER_YEAR = TPS_DAYS_PER_MONTH * TPS_MONTHS_PER_YEAR;
|
|
11
|
+
export const TPS_EPOCH_START_MS = Date.UTC(1999, 7, 11, 7, 0, 0, 0);
|
|
12
|
+
|
|
13
|
+
export type TpsIndexedParts = {
|
|
14
|
+
dayIndex: number;
|
|
15
|
+
dayFraction: number;
|
|
16
|
+
subDayMilliseconds: number;
|
|
17
|
+
fractionPrecision?: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function floorDiv(value: number, divisor: number): number {
|
|
21
|
+
return Math.floor(value / divisor);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function mod(value: number, divisor: number): number {
|
|
25
|
+
return ((value % divisor) + divisor) % divisor;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getFractionalMilliseconds(second: number | undefined): number {
|
|
29
|
+
if (second === undefined) return 0;
|
|
30
|
+
const fractional = second - Math.floor(second);
|
|
31
|
+
return Math.round(fractional * 1000);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function normalizeIndexedParts(
|
|
35
|
+
dayIndex: number,
|
|
36
|
+
dayFraction: number,
|
|
37
|
+
): TpsIndexedParts {
|
|
38
|
+
const roundedSubDayMilliseconds = Math.round(dayFraction * TPS_DAY_MS);
|
|
39
|
+
const dayCarry = floorDiv(roundedSubDayMilliseconds, TPS_DAY_MS);
|
|
40
|
+
const subDayMilliseconds = mod(roundedSubDayMilliseconds, TPS_DAY_MS);
|
|
41
|
+
const normalizedDayIndex = dayIndex + dayCarry;
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
dayIndex: normalizedDayIndex,
|
|
45
|
+
dayFraction: subDayMilliseconds / TPS_DAY_MS,
|
|
46
|
+
subDayMilliseconds,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function splitTpsFullYear(fullYear: number): {
|
|
51
|
+
millennium: number;
|
|
52
|
+
century: number;
|
|
53
|
+
year: number;
|
|
54
|
+
} {
|
|
55
|
+
const millennium = floorDiv(fullYear, 1000) + 1;
|
|
56
|
+
const withinMillennium = mod(fullYear, 1000);
|
|
57
|
+
const century = floorDiv(withinMillennium, 100) + 1;
|
|
58
|
+
const year = mod(fullYear, 100);
|
|
59
|
+
|
|
60
|
+
return { millennium, century, year };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function getTpsFullYear(components: Partial<TPSComponents>): number {
|
|
64
|
+
if (
|
|
65
|
+
components.millennium !== undefined ||
|
|
66
|
+
components.century !== undefined
|
|
67
|
+
) {
|
|
68
|
+
return (
|
|
69
|
+
((components.millennium ?? 1) - 1) * 1000 +
|
|
70
|
+
((components.century ?? 1) - 1) * 100 +
|
|
71
|
+
(components.year ?? 0)
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return components.year ?? 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function getTpsDayOfMonth(
|
|
79
|
+
components: Partial<TPSComponents>,
|
|
80
|
+
): number {
|
|
81
|
+
const day = components.day ?? 1;
|
|
82
|
+
const week = components.week;
|
|
83
|
+
|
|
84
|
+
if (week !== undefined && day >= 1 && day <= TPS_DAYS_PER_WEEK) {
|
|
85
|
+
return (week - 1) * TPS_DAYS_PER_WEEK + day;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return day;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function getTpsSubDayMilliseconds(
|
|
92
|
+
input: Date | Partial<TPSComponents>,
|
|
93
|
+
): number {
|
|
94
|
+
if (input instanceof Date) {
|
|
95
|
+
const indexed = getTpsIndexedFromDate(input);
|
|
96
|
+
return indexed.subDayMilliseconds;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (input.subDayMilliseconds !== undefined) {
|
|
100
|
+
return input.subDayMilliseconds;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const hour = input.hour ?? 0;
|
|
104
|
+
const minute = input.minute ?? 0;
|
|
105
|
+
const second = Math.floor(input.second ?? 0);
|
|
106
|
+
const millisecond =
|
|
107
|
+
input.millisecond ?? getFractionalMilliseconds(input.second);
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
hour * 60 * 60 * 1000 +
|
|
111
|
+
minute * 60 * 1000 +
|
|
112
|
+
second * 1000 +
|
|
113
|
+
millisecond
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function getTpsIndexedFromDate(date: Date): TpsIndexedParts {
|
|
118
|
+
const deltaMs = date.getTime() - TPS_EPOCH_START_MS;
|
|
119
|
+
const dayIndex = floorDiv(deltaMs, TPS_DAY_MS);
|
|
120
|
+
const subDayMilliseconds = mod(deltaMs, TPS_DAY_MS);
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
dayIndex,
|
|
124
|
+
dayFraction: subDayMilliseconds / TPS_DAY_MS,
|
|
125
|
+
subDayMilliseconds,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function buildTpsComponentsFromDayIndex(
|
|
130
|
+
dayIndex: number,
|
|
131
|
+
dayFraction: number = 0,
|
|
132
|
+
): Partial<TPSComponents> {
|
|
133
|
+
const indexed = normalizeIndexedParts(dayIndex, dayFraction);
|
|
134
|
+
const fullYear = floorDiv(indexed.dayIndex, TPS_DAYS_PER_YEAR);
|
|
135
|
+
const dayOfYear = mod(indexed.dayIndex, TPS_DAYS_PER_YEAR);
|
|
136
|
+
const month = floorDiv(dayOfYear, TPS_DAYS_PER_MONTH) + 1;
|
|
137
|
+
const dayOfMonth = mod(dayOfYear, TPS_DAYS_PER_MONTH) + 1;
|
|
138
|
+
const week = floorDiv(dayOfMonth - 1, TPS_DAYS_PER_WEEK) + 1;
|
|
139
|
+
|
|
140
|
+
let remainder = indexed.subDayMilliseconds;
|
|
141
|
+
const hour = floorDiv(remainder, 60 * 60 * 1000);
|
|
142
|
+
remainder = mod(remainder, 60 * 60 * 1000);
|
|
143
|
+
const minute = floorDiv(remainder, 60 * 1000);
|
|
144
|
+
remainder = mod(remainder, 60 * 1000);
|
|
145
|
+
const second = floorDiv(remainder, 1000);
|
|
146
|
+
const millisecond = mod(remainder, 1000);
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
calendar: "tps",
|
|
150
|
+
...splitTpsFullYear(fullYear),
|
|
151
|
+
month,
|
|
152
|
+
week,
|
|
153
|
+
day: dayOfMonth,
|
|
154
|
+
hour,
|
|
155
|
+
minute,
|
|
156
|
+
second,
|
|
157
|
+
millisecond,
|
|
158
|
+
dayIndex: indexed.dayIndex,
|
|
159
|
+
dayFraction: indexed.dayFraction,
|
|
160
|
+
subDayMilliseconds: indexed.subDayMilliseconds,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function normalizeTpsComponents(
|
|
165
|
+
components: Partial<TPSComponents>,
|
|
166
|
+
): Partial<TPSComponents> {
|
|
167
|
+
if (components.dayIndex !== undefined) {
|
|
168
|
+
const dayFraction =
|
|
169
|
+
components.dayFraction ??
|
|
170
|
+
(getTpsSubDayMilliseconds(components) / TPS_DAY_MS);
|
|
171
|
+
const normalized = buildTpsComponentsFromDayIndex(
|
|
172
|
+
components.dayIndex,
|
|
173
|
+
dayFraction,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
...components,
|
|
178
|
+
...normalized,
|
|
179
|
+
calendar: "tps",
|
|
180
|
+
fractionPrecision: components.fractionPrecision,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const fullYear = getTpsFullYear(components);
|
|
185
|
+
const month = components.month ?? 1;
|
|
186
|
+
const dayOfMonth = getTpsDayOfMonth(components);
|
|
187
|
+
const subDayMilliseconds = getTpsSubDayMilliseconds(components);
|
|
188
|
+
const week = components.week ?? floorDiv(dayOfMonth - 1, TPS_DAYS_PER_WEEK) + 1;
|
|
189
|
+
const timeParts = buildTpsComponentsFromDayIndex(
|
|
190
|
+
fullYear * TPS_DAYS_PER_YEAR +
|
|
191
|
+
(month - 1) * TPS_DAYS_PER_MONTH +
|
|
192
|
+
(dayOfMonth - 1),
|
|
193
|
+
subDayMilliseconds / TPS_DAY_MS,
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
...components,
|
|
198
|
+
...splitTpsFullYear(fullYear),
|
|
199
|
+
...timeParts,
|
|
200
|
+
calendar: "tps",
|
|
201
|
+
month,
|
|
202
|
+
week,
|
|
203
|
+
day: dayOfMonth,
|
|
204
|
+
dayIndex:
|
|
205
|
+
fullYear * TPS_DAYS_PER_YEAR +
|
|
206
|
+
(month - 1) * TPS_DAYS_PER_MONTH +
|
|
207
|
+
(dayOfMonth - 1),
|
|
208
|
+
dayFraction: subDayMilliseconds / TPS_DAY_MS,
|
|
209
|
+
subDayMilliseconds,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function getTpsDayIndex(
|
|
214
|
+
input: Date | Partial<TPSComponents>,
|
|
215
|
+
): number {
|
|
216
|
+
if (input instanceof Date) {
|
|
217
|
+
return getTpsIndexedFromDate(input).dayIndex;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (input.dayIndex !== undefined) {
|
|
221
|
+
return input.dayIndex;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const fullYear = getTpsFullYear(input);
|
|
225
|
+
const month = input.month ?? 1;
|
|
226
|
+
const dayOfMonth = getTpsDayOfMonth(input);
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
fullYear * TPS_DAYS_PER_YEAR +
|
|
230
|
+
(month - 1) * TPS_DAYS_PER_MONTH +
|
|
231
|
+
(dayOfMonth - 1)
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function getTpsDayFraction(
|
|
236
|
+
input: Date | Partial<TPSComponents>,
|
|
237
|
+
): number {
|
|
238
|
+
if (input instanceof Date) {
|
|
239
|
+
return getTpsIndexedFromDate(input).dayFraction;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (input.dayFraction !== undefined) {
|
|
243
|
+
return input.dayFraction;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return getTpsSubDayMilliseconds(input) / TPS_DAY_MS;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function parseTpsIndexedToken(token: string): TpsIndexedParts | null {
|
|
250
|
+
const match = token.trim().match(/^i(\d+)(?:\.(\d+))?$/i);
|
|
251
|
+
if (!match) return null;
|
|
252
|
+
|
|
253
|
+
const dayIndex = Number(match[1]);
|
|
254
|
+
if (!Number.isSafeInteger(dayIndex) || dayIndex < 0) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const digits = match[2];
|
|
259
|
+
if (digits && digits.endsWith("0")) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const dayFraction = digits ? Number(`0.${digits}`) : 0;
|
|
264
|
+
if (!Number.isFinite(dayFraction) || dayFraction < 0 || dayFraction >= 1) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const normalized = normalizeIndexedParts(dayIndex, dayFraction);
|
|
269
|
+
return {
|
|
270
|
+
...normalized,
|
|
271
|
+
fractionPrecision: digits?.length,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function formatTpsIndexedToken(
|
|
276
|
+
components: Partial<TPSComponents>,
|
|
277
|
+
precision?: number,
|
|
278
|
+
): string {
|
|
279
|
+
const normalized = normalizeTpsComponents(components);
|
|
280
|
+
const dayIndex = normalized.dayIndex ?? 0;
|
|
281
|
+
const dayFraction = normalized.dayFraction ?? 0;
|
|
282
|
+
|
|
283
|
+
const effectivePrecision =
|
|
284
|
+
precision ?? normalized.fractionPrecision ?? 9;
|
|
285
|
+
let fraction = "";
|
|
286
|
+
|
|
287
|
+
if (dayFraction > 0 && effectivePrecision > 0) {
|
|
288
|
+
fraction = dayFraction
|
|
289
|
+
.toFixed(effectivePrecision)
|
|
290
|
+
.slice(2)
|
|
291
|
+
.replace(/0+$/g, "");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return fraction ? `i${dayIndex}.${fraction}` : `i${dayIndex}`;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export function isTpsIndexedToken(token: string): boolean {
|
|
298
|
+
return /^i\d+(?:\.\d+)?$/i.test(token.trim());
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export function validateTpsComponents(
|
|
302
|
+
components: Partial<TPSComponents>,
|
|
303
|
+
): boolean {
|
|
304
|
+
const month = components.month ?? 1;
|
|
305
|
+
const day = components.day ?? 1;
|
|
306
|
+
const week = components.week;
|
|
307
|
+
const hour = components.hour ?? 0;
|
|
308
|
+
const minute = components.minute ?? 0;
|
|
309
|
+
const second = components.second ?? 0;
|
|
310
|
+
const millisecond =
|
|
311
|
+
components.millisecond ?? getFractionalMilliseconds(components.second);
|
|
312
|
+
|
|
313
|
+
if (
|
|
314
|
+
components.dayIndex !== undefined &&
|
|
315
|
+
(!Number.isSafeInteger(components.dayIndex) || components.dayIndex < 0)
|
|
316
|
+
) {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (
|
|
321
|
+
components.dayFraction !== undefined &&
|
|
322
|
+
(!Number.isFinite(components.dayFraction) ||
|
|
323
|
+
components.dayFraction < 0 ||
|
|
324
|
+
components.dayFraction >= 1)
|
|
325
|
+
) {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (month < 1 || month > TPS_MONTHS_PER_YEAR) return false;
|
|
330
|
+
if (day < 1 || day > TPS_DAYS_PER_MONTH) return false;
|
|
331
|
+
if (week !== undefined && (week < 1 || week > TPS_WEEKS_PER_MONTH)) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (week !== undefined && day > TPS_DAYS_PER_WEEK) {
|
|
336
|
+
const expectedWeek = floorDiv(day - 1, TPS_DAYS_PER_WEEK) + 1;
|
|
337
|
+
if (expectedWeek !== week) return false;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (hour < 0 || hour > 23) return false;
|
|
341
|
+
if (minute < 0 || minute > 59) return false;
|
|
342
|
+
if (second < 0 || second >= 60) return false;
|
|
343
|
+
if (millisecond < 0 || millisecond >= 1000) return false;
|
|
344
|
+
|
|
345
|
+
return true;
|
|
346
|
+
}
|
package/src/utils/tps-string.ts
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
TPSComponents,
|
|
3
|
+
TimeOrder,
|
|
4
|
+
DefaultCalendars,
|
|
5
|
+
TPSTimeOptions,
|
|
6
|
+
} from "../types";
|
|
7
|
+
import {
|
|
8
|
+
formatTpsIndexedToken,
|
|
9
|
+
isTpsIndexedToken,
|
|
10
|
+
normalizeTpsComponents,
|
|
11
|
+
parseTpsIndexedToken,
|
|
12
|
+
} from "./tps-native";
|
|
2
13
|
|
|
3
14
|
/**
|
|
4
15
|
* Generate the canonical `T:` time string for a set of components.
|
|
5
16
|
*/
|
|
6
|
-
export function buildTimePart(
|
|
17
|
+
export function buildTimePart(
|
|
18
|
+
comp: Partial<TPSComponents>,
|
|
19
|
+
options?: TPSTimeOptions,
|
|
20
|
+
): string {
|
|
7
21
|
const calendar = (comp.calendar || "").toLowerCase();
|
|
8
22
|
if (!/^[a-z]{3,4}$/.test(calendar)) {
|
|
9
23
|
throw new Error(
|
|
@@ -19,19 +33,35 @@ export function buildTimePart(comp: TPSComponents): string {
|
|
|
19
33
|
return time;
|
|
20
34
|
}
|
|
21
35
|
|
|
36
|
+
if (calendar === DefaultCalendars.TPS && options?.timeMode === "indexed-fraction") {
|
|
37
|
+
time += `.${formatTpsIndexedToken(comp, options.indexedPrecision)}`;
|
|
38
|
+
|
|
39
|
+
if (comp.signature) {
|
|
40
|
+
time += `!${comp.signature}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return time;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const source =
|
|
47
|
+
calendar === DefaultCalendars.TPS ? normalizeTpsComponents(comp) : comp;
|
|
48
|
+
|
|
22
49
|
const tokens: Array<[string, number | undefined, number]> = [
|
|
23
|
-
["m",
|
|
24
|
-
["c",
|
|
25
|
-
["y",
|
|
26
|
-
["m",
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
["
|
|
31
|
-
["
|
|
50
|
+
["m", source.millennium, 8],
|
|
51
|
+
["c", source.century, 7],
|
|
52
|
+
["y", source.year, 6],
|
|
53
|
+
["m", source.month, 5],
|
|
54
|
+
...(calendar === DefaultCalendars.TPS && source.week !== undefined
|
|
55
|
+
? [["w", source.week, 4.5] as [string, number | undefined, number]]
|
|
56
|
+
: []),
|
|
57
|
+
["d", source.day, 4],
|
|
58
|
+
["h", source.hour, 3],
|
|
59
|
+
["m", source.minute, 2],
|
|
60
|
+
["s", source.second, 1],
|
|
61
|
+
["m", source.millisecond, 0],
|
|
32
62
|
];
|
|
33
63
|
|
|
34
|
-
const order: TimeOrder =
|
|
64
|
+
const order: TimeOrder = options?.order || source.order || TimeOrder.DESC;
|
|
35
65
|
const activeTokens = order === TimeOrder.ASC ? [...tokens].reverse() : tokens;
|
|
36
66
|
|
|
37
67
|
for (const [pref, val] of activeTokens) {
|
|
@@ -40,8 +70,8 @@ export function buildTimePart(comp: TPSComponents): string {
|
|
|
40
70
|
}
|
|
41
71
|
}
|
|
42
72
|
|
|
43
|
-
if (
|
|
44
|
-
time += `!${
|
|
73
|
+
if (source.signature) {
|
|
74
|
+
time += `!${source.signature}`;
|
|
45
75
|
}
|
|
46
76
|
|
|
47
77
|
return time;
|
|
@@ -56,14 +86,35 @@ export function parseTimeString(
|
|
|
56
86
|
let s = input.trim();
|
|
57
87
|
s = s.split(/[!;?#]/)[0];
|
|
58
88
|
if (s.startsWith("T:")) s = s.slice(2);
|
|
89
|
+
|
|
90
|
+
const firstDot = s.indexOf(".");
|
|
91
|
+
const calendar = firstDot === -1 ? s : s.slice(0, firstDot);
|
|
92
|
+
const rawTokenString = firstDot === -1 ? "" : s.slice(firstDot + 1);
|
|
93
|
+
|
|
94
|
+
if (calendar === DefaultCalendars.TPS && isTpsIndexedToken(rawTokenString)) {
|
|
95
|
+
const indexed = parseTpsIndexedToken(rawTokenString);
|
|
96
|
+
if (!indexed) return null;
|
|
97
|
+
return {
|
|
98
|
+
components: normalizeTpsComponents({
|
|
99
|
+
calendar,
|
|
100
|
+
...indexed,
|
|
101
|
+
}),
|
|
102
|
+
order: TimeOrder.DESC,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (calendar === DefaultCalendars.TPS && /^i/i.test(rawTokenString)) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
59
110
|
const parts = s.split(".");
|
|
60
111
|
if (parts.length === 0) return null;
|
|
61
|
-
const calendar = parts[0];
|
|
62
112
|
const comp: Partial<TPSComponents> = { calendar };
|
|
63
113
|
|
|
64
114
|
const fixedRankMap: Record<string, number> = {
|
|
65
115
|
c: 7,
|
|
66
116
|
y: 6,
|
|
117
|
+
w: 4.5,
|
|
67
118
|
d: 4,
|
|
68
119
|
h: 3,
|
|
69
120
|
s: 1,
|
|
@@ -139,6 +190,9 @@ export function parseTimeString(
|
|
|
139
190
|
case "y":
|
|
140
191
|
comp.year = parseInt(value, 10);
|
|
141
192
|
break;
|
|
193
|
+
case "w":
|
|
194
|
+
comp.week = parseInt(value, 10);
|
|
195
|
+
break;
|
|
142
196
|
case "d":
|
|
143
197
|
comp.day = parseInt(value, 10);
|
|
144
198
|
break;
|
|
@@ -162,5 +216,18 @@ export function parseTimeString(
|
|
|
162
216
|
if (isAsc && !isDesc) order = TimeOrder.ASC;
|
|
163
217
|
}
|
|
164
218
|
|
|
219
|
+
if (
|
|
220
|
+
calendar === DefaultCalendars.TPS &&
|
|
221
|
+
comp.month !== undefined &&
|
|
222
|
+
comp.day !== undefined &&
|
|
223
|
+
comp.month >= 1 &&
|
|
224
|
+
comp.day >= 1
|
|
225
|
+
) {
|
|
226
|
+
return {
|
|
227
|
+
components: normalizeTpsComponents(comp),
|
|
228
|
+
order,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
165
232
|
return { components: comp, order };
|
|
166
233
|
}
|