@miso.ai/server-commons 0.6.5-beta.13 → 0.6.5-beta.15
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/package.json +4 -2
- package/src/date.js +95 -52
- package/test/date.test.js +31 -0
package/package.json
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
8
8
|
},
|
|
9
|
-
"scripts": {
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "npx uvu test -i 'ignored'"
|
|
11
|
+
},
|
|
10
12
|
"repository": "MisoAI/miso-server-js-sdk",
|
|
11
13
|
"license": "MIT",
|
|
12
14
|
"contributors": [
|
|
@@ -21,5 +23,5 @@
|
|
|
21
23
|
"uuid": "^9.0.0",
|
|
22
24
|
"yargs": "^17.5.1"
|
|
23
25
|
},
|
|
24
|
-
"version": "0.6.5-beta.
|
|
26
|
+
"version": "0.6.5-beta.15"
|
|
25
27
|
}
|
package/src/date.js
CHANGED
|
@@ -7,8 +7,6 @@ TS_PER_UNIT.m = TS_PER_UNIT.s * 60;
|
|
|
7
7
|
TS_PER_UNIT.h = TS_PER_UNIT.m * 60;
|
|
8
8
|
TS_PER_UNIT.d = TS_PER_UNIT.h * 24;
|
|
9
9
|
TS_PER_UNIT.w = TS_PER_UNIT.d * 7;
|
|
10
|
-
//TS_PER_UNIT.M = TS_PER_UNIT.d * 31;
|
|
11
|
-
//TS_PER_UNIT.y = TS_PER_UNIT.d * 366;
|
|
12
10
|
|
|
13
11
|
export function parseDuration(expr, unit) {
|
|
14
12
|
if (expr === undefined || typeof expr === 'number') {
|
|
@@ -33,69 +31,114 @@ export function getYear(dateStr) {
|
|
|
33
31
|
return new Date(dateStr).getFullYear();
|
|
34
32
|
}
|
|
35
33
|
|
|
34
|
+
const RE_DATE_EXPR = /^(?:\d{4})|(?:\d{4}-[Qq\d]\d)|(?:\d{4}-\d{2}-[Ww\d]\d)$/;
|
|
35
|
+
|
|
36
|
+
// TODO: support hour, minute
|
|
37
|
+
|
|
36
38
|
export function startOfDate(expr) {
|
|
37
39
|
if (expr === undefined) {
|
|
38
40
|
return undefined;
|
|
39
41
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
const parsed = parseDateExpr(expr);
|
|
43
|
+
switch (parsed.type) {
|
|
44
|
+
case 'ts':
|
|
45
|
+
return parsed.ts;
|
|
46
|
+
case 'year':
|
|
47
|
+
return Date.UTC(parsed.year);
|
|
48
|
+
case 'quarter':
|
|
49
|
+
return Date.UTC(parsed.year, (parsed.quarter - 1) * 3);
|
|
50
|
+
case 'month':
|
|
51
|
+
return Date.UTC(parsed.year, parsed.month - 1);
|
|
52
|
+
case 'week':
|
|
53
|
+
return Date.UTC(parsed.year, parsed.month - 1, (parsed.week - 1) * 7 + 1);
|
|
54
|
+
case 'day':
|
|
55
|
+
return Date.UTC(parsed.year, parsed.month - 1, parsed.day);
|
|
56
|
+
default:
|
|
57
|
+
throw new Error(`Unrecognized date: ${expr}`);
|
|
49
58
|
}
|
|
50
|
-
return ts;
|
|
51
59
|
}
|
|
52
60
|
|
|
53
|
-
|
|
54
|
-
const RE_MONTH = /^\d{4}-\d{2}$/g;
|
|
55
|
-
const RE_DATE = /^\d{4}-\d{2}-\d{2}$/g;
|
|
56
|
-
|
|
57
|
-
// TODO: support end of hour, minute
|
|
58
|
-
|
|
59
|
-
export function endOfDate(expr) {
|
|
61
|
+
export function nextOfDate(expr) {
|
|
60
62
|
if (expr === undefined) {
|
|
61
63
|
return undefined;
|
|
62
64
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
const parsed = parseDateExpr(expr);
|
|
66
|
+
switch (parsed.type) {
|
|
67
|
+
case 'ts':
|
|
68
|
+
return parsed.ts + 1;
|
|
69
|
+
case 'year':
|
|
70
|
+
return Date.UTC(parsed.year + 1);
|
|
71
|
+
case 'quarter':
|
|
72
|
+
return Date.UTC(parsed.year, parsed.quarter * 3);
|
|
73
|
+
case 'month':
|
|
74
|
+
return Date.UTC(parsed.year, parsed.month);
|
|
75
|
+
case 'week':
|
|
76
|
+
// roll over to 1st of next month if week is 4
|
|
77
|
+
return Date.UTC(parsed.year, parsed.week < 4 ? parsed.month - 1 : parsed.month, (parsed.week % 4) * 7 + 1);
|
|
78
|
+
case 'day':
|
|
79
|
+
return Date.UTC(parsed.year, parsed.month - 1, parsed.day + 1);
|
|
80
|
+
default:
|
|
81
|
+
throw new Error(`Unrecognized date: ${expr}`);
|
|
72
82
|
}
|
|
73
|
-
return expr.match(RE_YEAR) ? endOfYear(ts) :
|
|
74
|
-
expr.match(RE_MONTH) ? endOfMonth(ts) :
|
|
75
|
-
expr.match(RE_DATE) ? endOfDay(ts) : ts;
|
|
76
83
|
}
|
|
77
84
|
|
|
78
|
-
function
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return new Date(fullYear, 0, 1).getTime();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function endOfYearByYearNum(fullYear) {
|
|
87
|
-
return new Date(fullYear + 1, 0, 1).getTime() - 1000;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function endOfMonth(ts) {
|
|
91
|
-
const date = new Date(ts);
|
|
92
|
-
const year = date.getFullYear();
|
|
93
|
-
const month = date.getMonth();
|
|
94
|
-
return (month == 11 ? new Date(year + 1, 0, 1) : new Date(year, month + 1, 1)).getTime() - 1000;
|
|
85
|
+
export function endOfDate(expr) {
|
|
86
|
+
if (expr === undefined) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
return nextOfDate(expr) - 1000; // 1 sec
|
|
95
90
|
}
|
|
96
91
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
92
|
+
function parseDateExpr(expr) {
|
|
93
|
+
switch (typeof expr) {
|
|
94
|
+
case 'number':
|
|
95
|
+
if (expr < 100) {
|
|
96
|
+
throw new Error(`Unrecognized date: ${expr}`);
|
|
97
|
+
}
|
|
98
|
+
return expr < 10000 ? { type: 'year', year: expr } : { type: 'ts', ts: expr };
|
|
99
|
+
case 'string':
|
|
100
|
+
expr = expr.trim();
|
|
101
|
+
const len = expr.length;
|
|
102
|
+
if (!RE_DATE_EXPR.test(expr)) {
|
|
103
|
+
throw new Error(`Unrecognized date: ${expr}`);
|
|
104
|
+
}
|
|
105
|
+
const year = parseInt(expr.slice(0, 4), 10);
|
|
106
|
+
if (isNaN(year)) {
|
|
107
|
+
throw new Error(`Unrecognized date: ${expr}`);
|
|
108
|
+
}
|
|
109
|
+
if (len === 4) {
|
|
110
|
+
return { type: 'year', year };
|
|
111
|
+
}
|
|
112
|
+
if (len === 7 && (expr.charAt(5) === 'Q' || expr.charAt(5) === 'q')) {
|
|
113
|
+
const quarter = parseInt(expr.charAt(6), 10);
|
|
114
|
+
if (isNaN(quarter) || quarter < 1 || quarter > 4) {
|
|
115
|
+
throw new Error(`Unrecognized date: ${expr}`);
|
|
116
|
+
}
|
|
117
|
+
return { type: 'quarter', year, quarter };
|
|
118
|
+
}
|
|
119
|
+
const month = parseInt(expr.slice(5, 7), 10);
|
|
120
|
+
if (isNaN(month) || month < 1 || month > 12) {
|
|
121
|
+
throw new Error(`Unrecognized date: ${expr}`);
|
|
122
|
+
}
|
|
123
|
+
if (len === 7) {
|
|
124
|
+
return { type: 'month', year, month };
|
|
125
|
+
}
|
|
126
|
+
if (expr.charAt(8) === 'W' || expr.charAt(8) === 'w') {
|
|
127
|
+
const week = parseInt(expr.charAt(9), 10);
|
|
128
|
+
if (isNaN(week) || week < 1 || week > 4) {
|
|
129
|
+
throw new Error(`Unrecognized date: ${expr}`);
|
|
130
|
+
}
|
|
131
|
+
return { type: 'week', year, month, week };
|
|
132
|
+
}
|
|
133
|
+
let date;
|
|
134
|
+
try {
|
|
135
|
+
// parse so we can validate the day part
|
|
136
|
+
date = new Date(Date.parse(expr));
|
|
137
|
+
} catch (_) {
|
|
138
|
+
throw new Error(`Unrecognized date: ${expr}`);
|
|
139
|
+
}
|
|
140
|
+
return { type: 'day', year, month, day: date.getUTCDate() };
|
|
141
|
+
default:
|
|
142
|
+
throw new Error(`Unrecognized date: ${expr}`);
|
|
143
|
+
}
|
|
101
144
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { test } from 'uvu';
|
|
2
|
+
import * as assert from 'uvu/assert';
|
|
3
|
+
import { startOfDate, endOfDate } from '../src/index.js';
|
|
4
|
+
|
|
5
|
+
test('startOfDate', () => {
|
|
6
|
+
assert.equal(startOfDate('2025'), Date.parse('2025-01-01T00:00:00Z'));
|
|
7
|
+
assert.equal(startOfDate('2025-Q1'), Date.parse('2025-01-01T00:00:00Z'));
|
|
8
|
+
assert.equal(startOfDate('2025-q2'), Date.parse('2025-04-01T00:00:00Z'));
|
|
9
|
+
assert.equal(startOfDate('2025-Q3'), Date.parse('2025-07-01T00:00:00Z'));
|
|
10
|
+
assert.equal(startOfDate('2025-q4'), Date.parse('2025-10-01T00:00:00Z'));
|
|
11
|
+
assert.equal(startOfDate('2025-02'), Date.parse('2025-02-01T00:00:00Z'));
|
|
12
|
+
assert.equal(startOfDate('2025-02-W1'), Date.parse('2025-02-01T00:00:00Z'));
|
|
13
|
+
assert.equal(startOfDate('2025-02-w2'), Date.parse('2025-02-08T00:00:00Z'));
|
|
14
|
+
assert.equal(startOfDate('2025-02-03'), Date.parse('2025-02-03T00:00:00Z'));
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('endOfDate', () => {
|
|
18
|
+
assert.equal(endOfDate('2025'), Date.parse('2025-12-31T23:59:59Z'));
|
|
19
|
+
assert.equal(endOfDate('2025-Q1'), Date.parse('2025-03-31T23:59:59Z'));
|
|
20
|
+
assert.equal(endOfDate('2025-q2'), Date.parse('2025-06-30T23:59:59Z'));
|
|
21
|
+
assert.equal(endOfDate('2025-Q3'), Date.parse('2025-09-30T23:59:59Z'));
|
|
22
|
+
assert.equal(endOfDate('2025-q4'), Date.parse('2025-12-31T23:59:59Z'));
|
|
23
|
+
assert.equal(endOfDate('2025-02'), Date.parse('2025-02-28T23:59:59Z'));
|
|
24
|
+
assert.equal(endOfDate('2025-03-W1'), Date.parse('2025-03-07T23:59:59Z'));
|
|
25
|
+
assert.equal(endOfDate('2025-03-w2'), Date.parse('2025-03-14T23:59:59Z'));
|
|
26
|
+
assert.equal(endOfDate('2025-03-W3'), Date.parse('2025-03-21T23:59:59Z'));
|
|
27
|
+
assert.equal(endOfDate('2025-03-w4'), Date.parse('2025-03-31T23:59:59Z'));
|
|
28
|
+
assert.equal(endOfDate('2025-03-03'), Date.parse('2025-03-03T23:59:59Z'));
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test.run();
|