@terascope/core-utils 2.0.0-dev.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 +21 -0
- package/README.md +17 -0
- package/dist/src/arrays.d.ts +59 -0
- package/dist/src/arrays.d.ts.map +1 -0
- package/dist/src/arrays.js +180 -0
- package/dist/src/arrays.js.map +1 -0
- package/dist/src/big-lru-map.d.ts +14 -0
- package/dist/src/big-lru-map.d.ts.map +1 -0
- package/dist/src/big-lru-map.js +20 -0
- package/dist/src/big-lru-map.js.map +1 -0
- package/dist/src/big-map.d.ts +28 -0
- package/dist/src/big-map.d.ts.map +1 -0
- package/dist/src/big-map.js +148 -0
- package/dist/src/big-map.js.map +1 -0
- package/dist/src/big-set.d.ts +20 -0
- package/dist/src/big-set.d.ts.map +1 -0
- package/dist/src/big-set.js +109 -0
- package/dist/src/big-set.js.map +1 -0
- package/dist/src/booleans.d.ts +44 -0
- package/dist/src/booleans.d.ts.map +1 -0
- package/dist/src/booleans.js +81 -0
- package/dist/src/booleans.js.map +1 -0
- package/dist/src/buffers.d.ts +9 -0
- package/dist/src/buffers.d.ts.map +1 -0
- package/dist/src/buffers.js +22 -0
- package/dist/src/buffers.js.map +1 -0
- package/dist/src/collector.d.ts +48 -0
- package/dist/src/collector.d.ts.map +1 -0
- package/dist/src/collector.js +74 -0
- package/dist/src/collector.js.map +1 -0
- package/dist/src/dates.d.ts +180 -0
- package/dist/src/dates.d.ts.map +1 -0
- package/dist/src/dates.js +744 -0
- package/dist/src/dates.js.map +1 -0
- package/dist/src/decorators.d.ts +7 -0
- package/dist/src/decorators.d.ts.map +1 -0
- package/dist/src/decorators.js +21 -0
- package/dist/src/decorators.js.map +1 -0
- package/dist/src/deps.d.ts +25 -0
- package/dist/src/deps.d.ts.map +1 -0
- package/dist/src/deps.js +96 -0
- package/dist/src/deps.js.map +1 -0
- package/dist/src/empty.d.ts +11 -0
- package/dist/src/empty.d.ts.map +1 -0
- package/dist/src/empty.js +32 -0
- package/dist/src/empty.js.map +1 -0
- package/dist/src/entities/data-entity.d.ts +153 -0
- package/dist/src/entities/data-entity.d.ts.map +1 -0
- package/dist/src/entities/data-entity.js +354 -0
- package/dist/src/entities/data-entity.js.map +1 -0
- package/dist/src/entities/index.d.ts +3 -0
- package/dist/src/entities/index.d.ts.map +1 -0
- package/dist/src/entities/index.js +3 -0
- package/dist/src/entities/index.js.map +1 -0
- package/dist/src/entities/interfaces.d.ts +52 -0
- package/dist/src/entities/interfaces.d.ts.map +1 -0
- package/dist/src/entities/interfaces.js +13 -0
- package/dist/src/entities/interfaces.js.map +1 -0
- package/dist/src/entities/utils.d.ts +9 -0
- package/dist/src/entities/utils.d.ts.map +1 -0
- package/dist/src/entities/utils.js +44 -0
- package/dist/src/entities/utils.js.map +1 -0
- package/dist/src/env.d.ts +6 -0
- package/dist/src/env.d.ts.map +1 -0
- package/dist/src/env.js +15 -0
- package/dist/src/env.js.map +1 -0
- package/dist/src/equality.d.ts +72 -0
- package/dist/src/equality.d.ts.map +1 -0
- package/dist/src/equality.js +128 -0
- package/dist/src/equality.js.map +1 -0
- package/dist/src/errors.d.ts +140 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +372 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/event-loop.d.ts +33 -0
- package/dist/src/event-loop.d.ts.map +1 -0
- package/dist/src/event-loop.js +74 -0
- package/dist/src/event-loop.js.map +1 -0
- package/dist/src/fp.d.ts +15 -0
- package/dist/src/fp.d.ts.map +1 -0
- package/dist/src/fp.js +25 -0
- package/dist/src/fp.js.map +1 -0
- package/dist/src/functions.d.ts +19 -0
- package/dist/src/functions.d.ts.map +1 -0
- package/dist/src/functions.js +58 -0
- package/dist/src/functions.js.map +1 -0
- package/dist/src/index.d.ts +33 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +33 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/iterators.d.ts +9 -0
- package/dist/src/iterators.d.ts.map +1 -0
- package/dist/src/iterators.js +13 -0
- package/dist/src/iterators.js.map +1 -0
- package/dist/src/json.d.ts +8 -0
- package/dist/src/json.d.ts.map +1 -0
- package/dist/src/json.js +46 -0
- package/dist/src/json.js.map +1 -0
- package/dist/src/logger.d.ts +18 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +87 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/numbers.d.ts +86 -0
- package/dist/src/numbers.d.ts.map +1 -0
- package/dist/src/numbers.js +354 -0
- package/dist/src/numbers.js.map +1 -0
- package/dist/src/objects.d.ts +66 -0
- package/dist/src/objects.d.ts.map +1 -0
- package/dist/src/objects.js +170 -0
- package/dist/src/objects.js.map +1 -0
- package/dist/src/phone-number.d.ts +4 -0
- package/dist/src/phone-number.d.ts.map +1 -0
- package/dist/src/phone-number.js +31 -0
- package/dist/src/phone-number.js.map +1 -0
- package/dist/src/promises.d.ts +102 -0
- package/dist/src/promises.d.ts.map +1 -0
- package/dist/src/promises.js +289 -0
- package/dist/src/promises.js.map +1 -0
- package/dist/src/queue/index.d.ts +27 -0
- package/dist/src/queue/index.d.ts.map +1 -0
- package/dist/src/queue/index.js +170 -0
- package/dist/src/queue/index.js.map +1 -0
- package/dist/src/queue/node.d.ts +7 -0
- package/dist/src/queue/node.d.ts.map +1 -0
- package/dist/src/queue/node.js +17 -0
- package/dist/src/queue/node.js.map +1 -0
- package/dist/src/regex.d.ts +19 -0
- package/dist/src/regex.d.ts.map +1 -0
- package/dist/src/regex.js +138 -0
- package/dist/src/regex.js.map +1 -0
- package/dist/src/schemas.d.ts +69 -0
- package/dist/src/schemas.d.ts.map +1 -0
- package/dist/src/schemas.js +619 -0
- package/dist/src/schemas.js.map +1 -0
- package/dist/src/status-codes.d.ts +67 -0
- package/dist/src/status-codes.d.ts.map +1 -0
- package/dist/src/status-codes.js +66 -0
- package/dist/src/status-codes.js.map +1 -0
- package/dist/src/strings.d.ts +279 -0
- package/dist/src/strings.d.ts.map +1 -0
- package/dist/src/strings.js +578 -0
- package/dist/src/strings.js.map +1 -0
- package/dist/src/vector.d.ts +2 -0
- package/dist/src/vector.d.ts.map +1 -0
- package/dist/src/vector.js +16 -0
- package/dist/src/vector.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,744 @@
|
|
|
1
|
+
import validator from 'validator';
|
|
2
|
+
import parser from 'datemath-parser';
|
|
3
|
+
import { parse as parseDate, format as formatDate, differenceInMilliseconds, differenceInSeconds, differenceInMinutes, differenceInHours, differenceInDays, differenceInCalendarDays, differenceInBusinessDays, differenceInWeeks, differenceInCalendarISOWeeks, differenceInCalendarISOWeekYears, differenceInMonths, differenceInCalendarMonths, differenceInQuarters, differenceInCalendarQuarters, differenceInYears, differenceInCalendarYears, differenceInISOWeekYears, intervalToDuration, formatISODuration, isFuture as _isFuture, isPast as _isPast, isLeapYear as _isLeapYear, isToday as _isToday, isTomorrow as _isTomorrow, isYesterday as _isYesterday, add, sub, isBefore as _isBefore, isAfter as _isAfter, } from 'date-fns';
|
|
4
|
+
import { DateFormat, ISO8601DateSegment } from '@terascope/types';
|
|
5
|
+
import { getTimezoneOffset as tzOffset } from 'date-fns-tz';
|
|
6
|
+
import { isString } from './strings.js';
|
|
7
|
+
import { isNumber, toInteger, isInteger, inNumberRange, bigIntToJSON } from './numbers.js';
|
|
8
|
+
import { isBoolean } from './booleans.js';
|
|
9
|
+
import { getTypeOf } from './deps.js';
|
|
10
|
+
// date-fns doesn't handle utc correctly here
|
|
11
|
+
// https://github.com/date-fns/date-fns/issues/376
|
|
12
|
+
// https://github.com/date-fns/date-fns/blob/d0efa9eae1cf05c0e27461296b537b9dd46283d4/src/format/index.js#L399-L403
|
|
13
|
+
export const timezoneOffset = new Date().getTimezoneOffset() * 60_000;
|
|
14
|
+
/**
|
|
15
|
+
* A helper function for making an ISODate string
|
|
16
|
+
*/
|
|
17
|
+
export function makeISODate(value) {
|
|
18
|
+
if (value == null)
|
|
19
|
+
return new Date().toISOString();
|
|
20
|
+
const date = getValidDate(value);
|
|
21
|
+
if (date === false) {
|
|
22
|
+
throw new Error(`Invalid date ${date}`);
|
|
23
|
+
}
|
|
24
|
+
return date.toISOString();
|
|
25
|
+
}
|
|
26
|
+
/** A simplified implementation of moment(new Date(val)).isValid() */
|
|
27
|
+
export function isValidDate(val) {
|
|
28
|
+
return _getValidDate(val) !== false;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Coerces value into a valid date, returns false if it is invalid
|
|
32
|
+
*/
|
|
33
|
+
function _getValidDate(val) {
|
|
34
|
+
// this is our hot path since this is how commonly store this
|
|
35
|
+
if (typeof val === 'number') {
|
|
36
|
+
if (!Number.isInteger(val))
|
|
37
|
+
return false;
|
|
38
|
+
return new Date(val);
|
|
39
|
+
}
|
|
40
|
+
if (val == null || isBoolean(val))
|
|
41
|
+
return false;
|
|
42
|
+
if (val instanceof Date) {
|
|
43
|
+
if (!isValidDateInstance(val)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return val;
|
|
47
|
+
}
|
|
48
|
+
if (typeof val === 'bigint') {
|
|
49
|
+
// eslint-disable-next-line no-param-reassign
|
|
50
|
+
val = bigIntToJSON(val);
|
|
51
|
+
if (typeof val === 'string')
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (isDateTuple(val))
|
|
55
|
+
return new Date(val[0]);
|
|
56
|
+
const d = new Date(val);
|
|
57
|
+
if (isValidDateInstance(d))
|
|
58
|
+
return d;
|
|
59
|
+
// safari needs slashes when in month-date-year format
|
|
60
|
+
// don't call _getValidDate - could cause infinite loop
|
|
61
|
+
if (typeof val === 'string') {
|
|
62
|
+
const dashesToSlashes = new Date(val.replace(/-/g, '/'));
|
|
63
|
+
if (isValidDateInstance(dashesToSlashes)) {
|
|
64
|
+
return dashesToSlashes;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Coerces value into a valid date, returns false if it is invalid.
|
|
71
|
+
* Has added support for converting from date math (i.e. now+1h, now-1m, now+2d/y, 2021-01-01||+2d)
|
|
72
|
+
*/
|
|
73
|
+
export function getValidDate(val, relativeNow = new Date()) {
|
|
74
|
+
const validDate = _getValidDate(val);
|
|
75
|
+
if (validDate)
|
|
76
|
+
return validDate;
|
|
77
|
+
if (!relativeNow)
|
|
78
|
+
return false;
|
|
79
|
+
return parseRelativeDate(val, relativeNow);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* tries to date math values to dates
|
|
83
|
+
*/
|
|
84
|
+
function parseRelativeDate(input, now) {
|
|
85
|
+
if (!input || typeof input !== 'string')
|
|
86
|
+
return false;
|
|
87
|
+
// remove any spaces and ensure lowercase 'now' (keep all others normal case)
|
|
88
|
+
const trimmed = input.replace(/\s/g, '').replace(/(n|N)(o|O)(w|W)/g, 'now');
|
|
89
|
+
const dateMath = parseDateMath(trimmed, now);
|
|
90
|
+
if (dateMath)
|
|
91
|
+
return dateMath;
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* tries to parse date math (i.e. now+1h, now-1m) to a date
|
|
96
|
+
*/
|
|
97
|
+
function parseDateMath(value, now) {
|
|
98
|
+
try {
|
|
99
|
+
return _getValidDate(new Date(parser.parse(value, now)));
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Returns a valid date or throws, {@see getValidDate}
|
|
107
|
+
*/
|
|
108
|
+
export function getValidDateOrThrow(val) {
|
|
109
|
+
const date = getValidDate(val);
|
|
110
|
+
if (date === false) {
|
|
111
|
+
throw new TypeError(`Expected ${val} (${getTypeOf(val)}) to be in a standard date format`);
|
|
112
|
+
}
|
|
113
|
+
return date;
|
|
114
|
+
}
|
|
115
|
+
export function toTimeZone(val, timezone) {
|
|
116
|
+
if (!isString(timezone)) {
|
|
117
|
+
throw new Error(`Invalid argument timezone, it must be a string, got ${getTypeOf(timezone)}`);
|
|
118
|
+
}
|
|
119
|
+
const date = getValidDateOrThrow(val);
|
|
120
|
+
const offset = getTimezoneOffset(date, timezone);
|
|
121
|
+
// this should only fail right now in node v16, not v18
|
|
122
|
+
// as some timezones are not available in v16
|
|
123
|
+
if (isNaN(offset))
|
|
124
|
+
return null;
|
|
125
|
+
return setTimezone(date, offset);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* @returns date object from date tuple
|
|
129
|
+
*/
|
|
130
|
+
function _dateTupleToDateObject(val, getUTC = false) {
|
|
131
|
+
if (getUTC) {
|
|
132
|
+
return new Date(val[0]);
|
|
133
|
+
}
|
|
134
|
+
return new Date(val[0] + (val[1] * 60_000));
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Returns a valid date with the timezone applied or throws{@see getValidDate}
|
|
138
|
+
*/
|
|
139
|
+
export function getValidDateWithTimezoneOrThrow(val, getUTC = false) {
|
|
140
|
+
if (isDateTuple(val)) {
|
|
141
|
+
return _dateTupleToDateObject(val, getUTC);
|
|
142
|
+
}
|
|
143
|
+
// we don't pass getUTC here as this function ignores dateTuple timezone offsets for now
|
|
144
|
+
return getValidDateOrThrow(val);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Returns a valid date with the timezone applied {@see getValidDate}
|
|
148
|
+
*/
|
|
149
|
+
export function getValidDateWithTimezone(val, getUTC = false) {
|
|
150
|
+
if (isDateTuple(val)) {
|
|
151
|
+
return _dateTupleToDateObject(val, getUTC);
|
|
152
|
+
}
|
|
153
|
+
return getValidDate(val);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Returns a valid date or throws, {@see getValidDate}
|
|
157
|
+
*/
|
|
158
|
+
export function getValidDateOrNumberOrThrow(val) {
|
|
159
|
+
if (typeof val === 'number' && !Number.isInteger(val))
|
|
160
|
+
return val;
|
|
161
|
+
if (isDateTuple(val))
|
|
162
|
+
return val[0];
|
|
163
|
+
const date = getValidDate(val);
|
|
164
|
+
if (date === false) {
|
|
165
|
+
throw new TypeError(`Expected ${val} (${getTypeOf(val)}) to be in a standard date format`);
|
|
166
|
+
}
|
|
167
|
+
return date;
|
|
168
|
+
}
|
|
169
|
+
export function isValidDateInstance(val) {
|
|
170
|
+
// this has to use isNaN not Number.isNaN
|
|
171
|
+
return val instanceof Date && !isNaN(val);
|
|
172
|
+
}
|
|
173
|
+
/** Ensure unix time */
|
|
174
|
+
export function getTime(val) {
|
|
175
|
+
if (val == null)
|
|
176
|
+
return Date.now();
|
|
177
|
+
const result = getValidDate(val);
|
|
178
|
+
if (result === false)
|
|
179
|
+
return false;
|
|
180
|
+
return result.getTime();
|
|
181
|
+
}
|
|
182
|
+
export function getUnixTime(val) {
|
|
183
|
+
const time = getTime(val);
|
|
184
|
+
if (time !== false)
|
|
185
|
+
return Math.floor(time / 1000);
|
|
186
|
+
return time;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Checks to see if an input is a unix time
|
|
190
|
+
*/
|
|
191
|
+
export function isUnixTime(input, allowBefore1970 = true) {
|
|
192
|
+
const value = toInteger(input);
|
|
193
|
+
if (value === false)
|
|
194
|
+
return false;
|
|
195
|
+
if (allowBefore1970)
|
|
196
|
+
return true;
|
|
197
|
+
return value >= 0;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* A functional version of isUnixTime
|
|
201
|
+
*/
|
|
202
|
+
export function isUnixTimeFP(allowBefore1970) {
|
|
203
|
+
return function _isUnixTime(input) {
|
|
204
|
+
return isUnixTime(input, allowBefore1970);
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Checks to see if an input is a ISO 8601 date
|
|
209
|
+
*/
|
|
210
|
+
export function isISO8601(input) {
|
|
211
|
+
if (!isString(input))
|
|
212
|
+
return false;
|
|
213
|
+
return validator.isISO8601(input);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Convert a value to an ISO 8601 date string.
|
|
217
|
+
* This should be used over makeISODate
|
|
218
|
+
*/
|
|
219
|
+
export function toISO8601(value) {
|
|
220
|
+
if (isNumber(value)) {
|
|
221
|
+
return new Date(value).toISOString();
|
|
222
|
+
}
|
|
223
|
+
if (isDateTuple(value)) {
|
|
224
|
+
// this is utc so just fall back to
|
|
225
|
+
// to the correct timezone
|
|
226
|
+
if (value[1] === 0) {
|
|
227
|
+
return new Date(value[0]).toISOString();
|
|
228
|
+
}
|
|
229
|
+
// anytime we have a date tuple, manifest it in local time not UTC
|
|
230
|
+
const localTime = value[0] + (value[1] * 60_000);
|
|
231
|
+
return new Date(localTime).toISOString()
|
|
232
|
+
.replace('Z', _genISOTimezone(value[1]));
|
|
233
|
+
}
|
|
234
|
+
return makeISODate(value);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Generate the ISO8601
|
|
238
|
+
*/
|
|
239
|
+
function _genISOTimezone(offset) {
|
|
240
|
+
const absOffset = Math.abs(offset);
|
|
241
|
+
const hours = Math.floor(absOffset / 60);
|
|
242
|
+
const minutes = absOffset - (hours * 60);
|
|
243
|
+
const sign = offset < 0 ? '-' : '+';
|
|
244
|
+
return `${sign}${_padNum(hours)}:${_padNum(minutes)}`;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* a simple version of pad that only deals with simple cases
|
|
248
|
+
*/
|
|
249
|
+
function _padNum(input) {
|
|
250
|
+
return input < 10 ? `0${input}` : `${input}`;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Set the timezone offset of a date, returns a date tuple
|
|
254
|
+
*/
|
|
255
|
+
export function setTimezone(input, timezone) {
|
|
256
|
+
const validTZ = isNumber(timezone) ? timezone : timezoneToOffset(timezone);
|
|
257
|
+
return _makeDateTuple(input, validTZ);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* A curried version of setTimezone
|
|
261
|
+
*/
|
|
262
|
+
export function setTimezoneFP(timezone) {
|
|
263
|
+
const validTZ = isNumber(timezone) ? timezone : timezoneToOffset(timezone);
|
|
264
|
+
return function _setTimezone(input) {
|
|
265
|
+
return _makeDateTuple(input, validTZ);
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function _makeDateTuple(input, offset) {
|
|
269
|
+
if (isNumber(input))
|
|
270
|
+
return [input, offset];
|
|
271
|
+
if (isDateTuple(input))
|
|
272
|
+
return [input[0], offset];
|
|
273
|
+
const date = getValidDateOrThrow(input);
|
|
274
|
+
return [date.getTime(), offset];
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Verify if an input is a Date Tuple
|
|
278
|
+
*/
|
|
279
|
+
export function isDateTuple(input) {
|
|
280
|
+
return Array.isArray(input)
|
|
281
|
+
&& input.length === 2
|
|
282
|
+
&& Number.isInteger(input[0])
|
|
283
|
+
&& Number.isInteger(input[1])
|
|
284
|
+
// the timezone has to be within 24hours
|
|
285
|
+
// in minutes
|
|
286
|
+
&& input[1] <= 1440
|
|
287
|
+
&& input[1] >= -1440;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Returns a function to trim the ISO 8601 date segment
|
|
291
|
+
* useful for creating yearly, monthly, daily or hourly dates
|
|
292
|
+
*/
|
|
293
|
+
export function trimISODateSegment(segment) {
|
|
294
|
+
return function _trimISODate(input) {
|
|
295
|
+
const date = getValidDateWithTimezoneOrThrow(input, false);
|
|
296
|
+
if (segment === ISO8601DateSegment.hourly) {
|
|
297
|
+
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), 0, 0, 0)).getTime();
|
|
298
|
+
}
|
|
299
|
+
if (segment === ISO8601DateSegment.daily) {
|
|
300
|
+
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0, 0)).getTime();
|
|
301
|
+
}
|
|
302
|
+
if (segment === ISO8601DateSegment.monthly) {
|
|
303
|
+
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1, 0, 0, 0, 0)).getTime();
|
|
304
|
+
}
|
|
305
|
+
if (segment === ISO8601DateSegment.yearly) {
|
|
306
|
+
return new Date(Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0)).getTime();
|
|
307
|
+
}
|
|
308
|
+
throw new Error(`Invalid segment "${segment}" given`);
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* track a timeout to see if it expires
|
|
313
|
+
* @returns a function that will returns false if the time elapsed
|
|
314
|
+
*/
|
|
315
|
+
export function trackTimeout(timeoutMs) {
|
|
316
|
+
const startTime = Date.now();
|
|
317
|
+
return () => {
|
|
318
|
+
const elapsed = Date.now() - startTime;
|
|
319
|
+
if (timeoutMs > -1 && elapsed > timeoutMs) {
|
|
320
|
+
return elapsed;
|
|
321
|
+
}
|
|
322
|
+
return false;
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
/** converts smaller than a week milliseconds to human readable time */
|
|
326
|
+
export function toHumanTime(ms) {
|
|
327
|
+
const ONE_SEC = 1000;
|
|
328
|
+
const ONE_MIN = ONE_SEC * 60;
|
|
329
|
+
const ONE_HOUR = ONE_MIN * 60;
|
|
330
|
+
const ONE_DAY = ONE_HOUR * 24;
|
|
331
|
+
const minOver = 1.5;
|
|
332
|
+
if (ms > ONE_DAY * minOver && ms < ONE_DAY * 7) {
|
|
333
|
+
return `${Math.round((ms * 100) / ONE_DAY) / 100}day`;
|
|
334
|
+
}
|
|
335
|
+
if (ms > ONE_HOUR * minOver)
|
|
336
|
+
return `${Math.round((ms * 100) / ONE_HOUR) / 100}hr`;
|
|
337
|
+
if (ms > ONE_MIN * minOver)
|
|
338
|
+
return `${Math.round((ms * 100) / ONE_MIN) / 100}min`;
|
|
339
|
+
if (ms > ONE_SEC * minOver) {
|
|
340
|
+
return `${Math.round((ms * 100) / ONE_SEC) / 100}sec`;
|
|
341
|
+
}
|
|
342
|
+
if (ms < ONE_SEC * minOver) {
|
|
343
|
+
return `${Math.round(ms)}ms`;
|
|
344
|
+
}
|
|
345
|
+
return `${Math.round((ms * 100) / ONE_DAY) / 100}day`;
|
|
346
|
+
}
|
|
347
|
+
export function parseCustomDateFormat(value, format, referenceDate) {
|
|
348
|
+
if (typeof value !== 'string') {
|
|
349
|
+
throw new Error(`Expected string for formatted date fields, got ${value}`);
|
|
350
|
+
}
|
|
351
|
+
const hasTimezoneFormat = format.match(/[xX]/);
|
|
352
|
+
const date = parseDate(value, format, referenceDate);
|
|
353
|
+
if (!isValidDateInstance(date)) {
|
|
354
|
+
throw new Error(`Expected value ${value} to be a date string with format ${format}`);
|
|
355
|
+
}
|
|
356
|
+
// the format indicates its already UTC conversion
|
|
357
|
+
if (hasTimezoneFormat)
|
|
358
|
+
return date.getTime();
|
|
359
|
+
// need subtract the date offset here to
|
|
360
|
+
// in order to deal with UTC time
|
|
361
|
+
return date.getTime() - timezoneOffset;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Parse a date value (that has already been validated)
|
|
365
|
+
* and return the epoch millis time.
|
|
366
|
+
*/
|
|
367
|
+
export function parseDateValue(value, format, referenceDate) {
|
|
368
|
+
if (format === DateFormat.epoch || format === DateFormat.seconds) {
|
|
369
|
+
const int = toInteger(value);
|
|
370
|
+
if (int === false) {
|
|
371
|
+
throw new Error(`Expected value ${value} to be a valid time`);
|
|
372
|
+
}
|
|
373
|
+
return Math.floor(int * 1000);
|
|
374
|
+
}
|
|
375
|
+
if (format && !(format in DateFormat)) {
|
|
376
|
+
return parseCustomDateFormat(value, format, referenceDate);
|
|
377
|
+
}
|
|
378
|
+
const result = getTime(value);
|
|
379
|
+
if (result === false) {
|
|
380
|
+
throw new Error(`Expected value ${value} to be a valid date`);
|
|
381
|
+
}
|
|
382
|
+
return result;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Format the parsed date value
|
|
386
|
+
*/
|
|
387
|
+
export function formatDateValue(value, format) {
|
|
388
|
+
const inMs = _toMilliseconds(value);
|
|
389
|
+
if (format === DateFormat.epoch_millis || format === DateFormat.milliseconds) {
|
|
390
|
+
return inMs;
|
|
391
|
+
}
|
|
392
|
+
if (format === DateFormat.epoch || format === DateFormat.seconds) {
|
|
393
|
+
return Math.floor(inMs / 1000);
|
|
394
|
+
}
|
|
395
|
+
if (format && !(format in DateFormat)) {
|
|
396
|
+
const inputValue = format.match(/[xX]/) ? inMs : inMs + timezoneOffset;
|
|
397
|
+
// need add our offset here to
|
|
398
|
+
// deal with UTC time
|
|
399
|
+
return formatDate(inputValue, format);
|
|
400
|
+
}
|
|
401
|
+
return toISO8601(value);
|
|
402
|
+
}
|
|
403
|
+
function _toMilliseconds(value) {
|
|
404
|
+
if (isDateTuple(value))
|
|
405
|
+
return value[0];
|
|
406
|
+
return value instanceof Date ? value.getTime() : value;
|
|
407
|
+
}
|
|
408
|
+
export const getDurationFunc = {
|
|
409
|
+
milliseconds: differenceInMilliseconds,
|
|
410
|
+
seconds: differenceInSeconds,
|
|
411
|
+
minutes: differenceInMinutes,
|
|
412
|
+
hours: differenceInHours,
|
|
413
|
+
days: differenceInDays,
|
|
414
|
+
calendarDays: differenceInCalendarDays,
|
|
415
|
+
businessDays: differenceInBusinessDays,
|
|
416
|
+
weeks: differenceInWeeks,
|
|
417
|
+
calendarWeeks: differenceInCalendarISOWeeks,
|
|
418
|
+
months: differenceInMonths,
|
|
419
|
+
calendarMonths: differenceInCalendarMonths,
|
|
420
|
+
quarters: differenceInQuarters,
|
|
421
|
+
calendarQuarters: differenceInCalendarQuarters,
|
|
422
|
+
years: differenceInYears,
|
|
423
|
+
calendarYears: differenceInCalendarYears,
|
|
424
|
+
calendarISOWeekYears: differenceInCalendarISOWeekYears,
|
|
425
|
+
ISOWeekYears: differenceInISOWeekYears
|
|
426
|
+
};
|
|
427
|
+
export function getTimeBetween(input, args) {
|
|
428
|
+
const { interval } = args;
|
|
429
|
+
const [time1, time2] = _getStartEndTime(input, args);
|
|
430
|
+
const date1 = getValidDateWithTimezoneOrThrow(time1, false);
|
|
431
|
+
const date2 = getValidDateWithTimezoneOrThrow(time2, false);
|
|
432
|
+
if (interval === 'ISO8601') {
|
|
433
|
+
return formatISODuration(intervalToDuration({
|
|
434
|
+
start: date1,
|
|
435
|
+
end: date2
|
|
436
|
+
}));
|
|
437
|
+
}
|
|
438
|
+
return getDurationFunc[interval](date2, date1);
|
|
439
|
+
}
|
|
440
|
+
function _getStartEndTime(input, args) {
|
|
441
|
+
const { start, end } = args;
|
|
442
|
+
if (start == null && end == null) {
|
|
443
|
+
throw Error('Must provide a start or an end argument');
|
|
444
|
+
}
|
|
445
|
+
if (start)
|
|
446
|
+
return [start, input];
|
|
447
|
+
return [input, end];
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* A functional version of getTimeBetween
|
|
451
|
+
*/
|
|
452
|
+
export function getTimeBetweenFP(args) {
|
|
453
|
+
return function _getTimeBetween(input) {
|
|
454
|
+
return getTimeBetween(input, args);
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
export function isSunday(input) {
|
|
458
|
+
const date = getValidDateWithTimezone(input, false);
|
|
459
|
+
if (!date)
|
|
460
|
+
return false;
|
|
461
|
+
return date.getDay() === 0;
|
|
462
|
+
}
|
|
463
|
+
export function isMonday(input) {
|
|
464
|
+
const date = getValidDateWithTimezone(input, false);
|
|
465
|
+
if (!date)
|
|
466
|
+
return false;
|
|
467
|
+
return date.getDay() === 1;
|
|
468
|
+
}
|
|
469
|
+
export function isTuesday(input) {
|
|
470
|
+
const date = getValidDateWithTimezone(input, false);
|
|
471
|
+
if (!date)
|
|
472
|
+
return false;
|
|
473
|
+
return date.getDay() === 2;
|
|
474
|
+
}
|
|
475
|
+
export function isWednesday(input) {
|
|
476
|
+
const date = getValidDateWithTimezone(input, false);
|
|
477
|
+
if (!date)
|
|
478
|
+
return false;
|
|
479
|
+
return date.getDay() === 3;
|
|
480
|
+
}
|
|
481
|
+
export function isThursday(input) {
|
|
482
|
+
const date = getValidDateWithTimezone(input, false);
|
|
483
|
+
if (!date)
|
|
484
|
+
return false;
|
|
485
|
+
return date.getDay() === 4;
|
|
486
|
+
}
|
|
487
|
+
export function isFriday(input) {
|
|
488
|
+
const date = getValidDateWithTimezone(input, false);
|
|
489
|
+
if (!date)
|
|
490
|
+
return false;
|
|
491
|
+
return date.getDay() === 5;
|
|
492
|
+
}
|
|
493
|
+
export function isSaturday(input) {
|
|
494
|
+
const date = getValidDateWithTimezone(input, false);
|
|
495
|
+
if (!date)
|
|
496
|
+
return false;
|
|
497
|
+
return date.getDay() === 6;
|
|
498
|
+
}
|
|
499
|
+
export function isWeekday(input) {
|
|
500
|
+
const date = getValidDateWithTimezone(input, false);
|
|
501
|
+
if (!date)
|
|
502
|
+
return false;
|
|
503
|
+
const day = date.getDay();
|
|
504
|
+
return day >= 1 && day <= 5;
|
|
505
|
+
}
|
|
506
|
+
export function isWeekend(input) {
|
|
507
|
+
const date = getValidDateWithTimezone(input, false);
|
|
508
|
+
if (!date)
|
|
509
|
+
return false;
|
|
510
|
+
const day = date.getDay();
|
|
511
|
+
return day === 0 || day === 6;
|
|
512
|
+
}
|
|
513
|
+
export function isFuture(input) {
|
|
514
|
+
const date = getValidDateWithTimezone(input, false);
|
|
515
|
+
if (!date)
|
|
516
|
+
return false;
|
|
517
|
+
return _isFuture(date);
|
|
518
|
+
}
|
|
519
|
+
export function isPast(input) {
|
|
520
|
+
const date = getValidDateWithTimezone(input, false);
|
|
521
|
+
if (!date)
|
|
522
|
+
return false;
|
|
523
|
+
return _isPast(date);
|
|
524
|
+
}
|
|
525
|
+
export function isLeapYear(input) {
|
|
526
|
+
const date = getValidDateWithTimezone(input, false);
|
|
527
|
+
if (!date)
|
|
528
|
+
return false;
|
|
529
|
+
return _isLeapYear(date);
|
|
530
|
+
}
|
|
531
|
+
export function isTomorrow(input) {
|
|
532
|
+
const date = getValidDateWithTimezone(input, false);
|
|
533
|
+
if (!date)
|
|
534
|
+
return false;
|
|
535
|
+
return _isTomorrow(date);
|
|
536
|
+
}
|
|
537
|
+
export function isToday(input) {
|
|
538
|
+
const date = getValidDateWithTimezone(input, false);
|
|
539
|
+
if (!date)
|
|
540
|
+
return false;
|
|
541
|
+
return _isToday(date);
|
|
542
|
+
}
|
|
543
|
+
export function isYesterday(input) {
|
|
544
|
+
const date = getValidDateWithTimezone(input, false);
|
|
545
|
+
if (!date)
|
|
546
|
+
return false;
|
|
547
|
+
return _isYesterday(date);
|
|
548
|
+
}
|
|
549
|
+
export function addToDate(input, args) {
|
|
550
|
+
const date = getValidDateWithTimezoneOrThrow(input, false);
|
|
551
|
+
if ('expr' in args) {
|
|
552
|
+
return parser.parse(`now+${args.expr}`, date);
|
|
553
|
+
}
|
|
554
|
+
return add(date, args).getTime();
|
|
555
|
+
}
|
|
556
|
+
export function addToDateFP(args) {
|
|
557
|
+
return function _addToDateFP(input) {
|
|
558
|
+
return addToDate(input, args);
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
export function subtractFromDate(input, args) {
|
|
562
|
+
const date = getValidDateWithTimezoneOrThrow(input, false);
|
|
563
|
+
if ('expr' in args) {
|
|
564
|
+
return parser.parse(`now-${args.expr}`, date);
|
|
565
|
+
}
|
|
566
|
+
return sub(date, args).getTime();
|
|
567
|
+
}
|
|
568
|
+
export function subtractFromDateFP(args) {
|
|
569
|
+
return function _subtractFromDateFP(input) {
|
|
570
|
+
return subtractFromDate(input, args);
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
export function isBefore(input, date) {
|
|
574
|
+
const date1 = getValidDateWithTimezone(input, false);
|
|
575
|
+
const date2 = getValidDateWithTimezone(date, false);
|
|
576
|
+
if (date1 && date2) {
|
|
577
|
+
return _isBefore(date1, date2);
|
|
578
|
+
}
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
export function isAfter(input, date) {
|
|
582
|
+
const date1 = getValidDateWithTimezone(input, false);
|
|
583
|
+
const date2 = getValidDateWithTimezone(date, false);
|
|
584
|
+
if (date1 && date2) {
|
|
585
|
+
return _isAfter(date1, date2);
|
|
586
|
+
}
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
export function isBetween(input, args) {
|
|
590
|
+
const { start, end } = args;
|
|
591
|
+
const inputDate = getValidDateWithTimezone(input, false);
|
|
592
|
+
const date1 = getValidDateWithTimezone(start, false);
|
|
593
|
+
const date2 = getValidDateWithTimezone(end, false);
|
|
594
|
+
if (inputDate && date1 && date2) {
|
|
595
|
+
return _isAfter(inputDate, date1) && _isBefore(inputDate, date2);
|
|
596
|
+
}
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
/** Given a timezone, it will return the minutes of its offset from UTC time */
|
|
600
|
+
export function timezoneToOffset(timezone) {
|
|
601
|
+
if (!isString(timezone)) {
|
|
602
|
+
throw new Error(`Invalid argument timezone, it must be a string, got ${getTypeOf(timezone)}`);
|
|
603
|
+
}
|
|
604
|
+
return Math.round(tzOffset(timezone) / (1000 * 60));
|
|
605
|
+
}
|
|
606
|
+
/** Given a date and timezone, it will return the offset from UTC in minutes.
|
|
607
|
+
* This is more accurate than timezoneToOffset as it can better account for day lights saving time
|
|
608
|
+
* */
|
|
609
|
+
export function getTimezoneOffset(input, timezone) {
|
|
610
|
+
const date = getValidDateOrThrow(input);
|
|
611
|
+
if (!isString(timezone)) {
|
|
612
|
+
throw new Error(`Invalid argument timezone, it must be a string, got ${getTypeOf(timezone)}`);
|
|
613
|
+
}
|
|
614
|
+
return Math.round(tzOffset(timezone, date) / (1000 * 60));
|
|
615
|
+
}
|
|
616
|
+
/** Given a timezone, it will return a function that will take in dates that will
|
|
617
|
+
* be converted the offset in minutes. This is more accurate than timezoneToOffset
|
|
618
|
+
* as it can better account for day lights saving time
|
|
619
|
+
* */
|
|
620
|
+
export function getTimezoneOffsetFP(timezone) {
|
|
621
|
+
if (!isString(timezone)) {
|
|
622
|
+
throw new Error(`Invalid argument timezone, it must be a string, got ${getTypeOf(timezone)}`);
|
|
623
|
+
}
|
|
624
|
+
return function _getTimezoneOffsetFP(input) {
|
|
625
|
+
const date = getValidDateOrThrow(input);
|
|
626
|
+
return Math.round(tzOffset(timezone, date) / (1000 * 60));
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
export function setMilliseconds(ms) {
|
|
630
|
+
if (!isInteger(ms) || !inNumberRange(ms, { min: 0, max: 999, inclusive: true })) {
|
|
631
|
+
throw Error(`milliseconds value must be an integer between 0 and 999, received ${ms}`);
|
|
632
|
+
}
|
|
633
|
+
return function _setMilliseconds(input) {
|
|
634
|
+
const inputDate = getValidDateOrThrow(input);
|
|
635
|
+
return inputDate.setUTCMilliseconds(ms);
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
export function setSeconds(seconds) {
|
|
639
|
+
if (!isInteger(seconds) || !inNumberRange(seconds, { min: 0, max: 59, inclusive: true })) {
|
|
640
|
+
throw Error(`seconds value must be an integer between 0 and 59, received ${seconds}`);
|
|
641
|
+
}
|
|
642
|
+
return function _setSeconds(input) {
|
|
643
|
+
const inputDate = getValidDateOrThrow(input);
|
|
644
|
+
return inputDate.setUTCSeconds(seconds);
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
export function setMinutes(minutes) {
|
|
648
|
+
if (!isInteger(minutes) || !inNumberRange(minutes, { min: 0, max: 59, inclusive: true })) {
|
|
649
|
+
throw Error(`minutes value must be an integer between 0 and 59, received ${minutes}`);
|
|
650
|
+
}
|
|
651
|
+
return function _setMinutes(input) {
|
|
652
|
+
const inputDate = getValidDateWithTimezoneOrThrow(input, false);
|
|
653
|
+
return inputDate.setUTCMinutes(minutes);
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
export function setHours(hours) {
|
|
657
|
+
if (!isInteger(hours) || !inNumberRange(hours, { min: 0, max: 23, inclusive: true })) {
|
|
658
|
+
throw Error(`hours value must be an integer between 0 and 23, received ${hours}`);
|
|
659
|
+
}
|
|
660
|
+
return function _setHours(input) {
|
|
661
|
+
const inputDate = getValidDateWithTimezoneOrThrow(input, false);
|
|
662
|
+
return inputDate.setUTCHours(hours);
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
export function setDate(date) {
|
|
666
|
+
if (!isInteger(date) || !inNumberRange(date, { min: 1, max: 31, inclusive: true })) {
|
|
667
|
+
throw Error(`date value must be an integer between 1 and 31, received ${date}`);
|
|
668
|
+
}
|
|
669
|
+
return function _setDate(input) {
|
|
670
|
+
const inputDate = getValidDateWithTimezoneOrThrow(input, false);
|
|
671
|
+
return inputDate.setUTCDate(date);
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
export function setMonth(month) {
|
|
675
|
+
if (!isInteger(month) || !inNumberRange(month, { min: 1, max: 12, inclusive: true })) {
|
|
676
|
+
throw Error(`month value must be an integer between 1 and 12, received ${month}`);
|
|
677
|
+
}
|
|
678
|
+
return function _setMonth(input) {
|
|
679
|
+
const inputDate = getValidDateWithTimezoneOrThrow(input, false);
|
|
680
|
+
return inputDate.setUTCMonth(month - 1);
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
export function setYear(year) {
|
|
684
|
+
if (!isInteger(year)) {
|
|
685
|
+
throw Error(`year value must be an integer, received ${year}`);
|
|
686
|
+
}
|
|
687
|
+
return function _setYear(input) {
|
|
688
|
+
const inputDate = getValidDateWithTimezoneOrThrow(input, false);
|
|
689
|
+
return inputDate.setUTCFullYear(year);
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
export function getMilliseconds(input) {
|
|
693
|
+
return getValidDateOrThrow(input).getUTCMilliseconds();
|
|
694
|
+
}
|
|
695
|
+
export function getSeconds(input) {
|
|
696
|
+
return getValidDateOrThrow(input).getUTCSeconds();
|
|
697
|
+
}
|
|
698
|
+
export function getUTCMinutes(input) {
|
|
699
|
+
const date = getValidDateWithTimezoneOrThrow(input, true);
|
|
700
|
+
return date.getUTCMinutes();
|
|
701
|
+
}
|
|
702
|
+
export function getMinutes(input) {
|
|
703
|
+
const date = getValidDateWithTimezoneOrThrow(input, false);
|
|
704
|
+
return date.getUTCMinutes();
|
|
705
|
+
}
|
|
706
|
+
export function getUTCHours(input) {
|
|
707
|
+
const date = getValidDateWithTimezoneOrThrow(input, true);
|
|
708
|
+
return date.getUTCHours();
|
|
709
|
+
}
|
|
710
|
+
export function getHours(input) {
|
|
711
|
+
const date = getValidDateWithTimezoneOrThrow(input, false);
|
|
712
|
+
return date.getUTCHours();
|
|
713
|
+
}
|
|
714
|
+
export function getUTCDate(input) {
|
|
715
|
+
const date = getValidDateWithTimezoneOrThrow(input, true);
|
|
716
|
+
return date.getUTCDate();
|
|
717
|
+
}
|
|
718
|
+
export function getDate(input) {
|
|
719
|
+
const date = getValidDateWithTimezoneOrThrow(input, false);
|
|
720
|
+
return date.getUTCDate();
|
|
721
|
+
}
|
|
722
|
+
export function getUTCMonth(input) {
|
|
723
|
+
return getValidDateWithTimezoneOrThrow(input, true).getUTCMonth() + 1;
|
|
724
|
+
}
|
|
725
|
+
export function getMonth(input) {
|
|
726
|
+
return getValidDateWithTimezoneOrThrow(input, false).getUTCMonth() + 1;
|
|
727
|
+
}
|
|
728
|
+
export function getUTCYear(input) {
|
|
729
|
+
return getValidDateWithTimezoneOrThrow(input, true).getUTCFullYear();
|
|
730
|
+
}
|
|
731
|
+
export function getYear(input) {
|
|
732
|
+
return getValidDateWithTimezoneOrThrow(input, false).getUTCFullYear();
|
|
733
|
+
}
|
|
734
|
+
/** Will convert a date to its epoch millisecond format or throw if invalid */
|
|
735
|
+
export function toEpochMSOrThrow(input) {
|
|
736
|
+
if (isDateTuple(input))
|
|
737
|
+
return input;
|
|
738
|
+
const epochMillis = getTime(input);
|
|
739
|
+
if (epochMillis === false) {
|
|
740
|
+
throw new TypeError(`Expected ${input} (${getTypeOf(input)}) to be a standard date value`);
|
|
741
|
+
}
|
|
742
|
+
return epochMillis;
|
|
743
|
+
}
|
|
744
|
+
//# sourceMappingURL=dates.js.map
|