feelin 4.3.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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/feelin.gemspec +22 -0
- data/lib/feelin/js/node_modules/.package-lock.json +67 -0
- data/lib/feelin/js/node_modules/@lezer/common/LICENSE +21 -0
- data/lib/feelin/js/node_modules/@lezer/common/README.md +14 -0
- data/lib/feelin/js/node_modules/@lezer/common/dist/index.cjs +2181 -0
- data/lib/feelin/js/node_modules/@lezer/common/dist/index.d.cts +1137 -0
- data/lib/feelin/js/node_modules/@lezer/common/dist/index.d.ts +1137 -0
- data/lib/feelin/js/node_modules/@lezer/common/dist/index.js +2168 -0
- data/lib/feelin/js/node_modules/@lezer/common/package.json +32 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/LICENSE +21 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/README.md +14 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/dist/index.cjs +915 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/dist/index.d.cts +621 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/dist/index.d.ts +623 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/dist/index.js +904 -0
- data/lib/feelin/js/node_modules/@lezer/highlight/package.json +31 -0
- data/lib/feelin/js/node_modules/@lezer/lr/LICENSE +21 -0
- data/lib/feelin/js/node_modules/@lezer/lr/README.md +25 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/constants.d.ts +45 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/constants.js +5 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/index.cjs +1890 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/index.d.cts +303 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/index.d.ts +303 -0
- data/lib/feelin/js/node_modules/@lezer/lr/dist/index.js +1883 -0
- data/lib/feelin/js/node_modules/@lezer/lr/package.json +32 -0
- data/lib/feelin/js/node_modules/feelin/LICENSE +21 -0
- data/lib/feelin/js/node_modules/feelin/README.md +65 -0
- data/lib/feelin/js/node_modules/feelin/dist/builtins.d.ts +355 -0
- data/lib/feelin/js/node_modules/feelin/dist/index.cjs +2072 -0
- data/lib/feelin/js/node_modules/feelin/dist/index.cjs.map +1 -0
- data/lib/feelin/js/node_modules/feelin/dist/index.d.ts +3 -0
- data/lib/feelin/js/node_modules/feelin/dist/index.esm.js +2063 -0
- data/lib/feelin/js/node_modules/feelin/dist/index.esm.js.map +1 -0
- data/lib/feelin/js/node_modules/feelin/dist/interpreter.d.ts +26 -0
- data/lib/feelin/js/node_modules/feelin/dist/parser.d.ts +4 -0
- data/lib/feelin/js/node_modules/feelin/dist/temporal.d.ts +6 -0
- data/lib/feelin/js/node_modules/feelin/dist/types.d.ts +35 -0
- data/lib/feelin/js/node_modules/feelin/dist/utils.d.ts +12 -0
- data/lib/feelin/js/node_modules/feelin/package.json +63 -0
- data/lib/feelin/js/node_modules/lezer-feel/LICENSE +21 -0
- data/lib/feelin/js/node_modules/lezer-feel/README.md +94 -0
- data/lib/feelin/js/node_modules/lezer-feel/dist/index.cjs +1328 -0
- data/lib/feelin/js/node_modules/lezer-feel/dist/index.cjs.map +1 -0
- data/lib/feelin/js/node_modules/lezer-feel/dist/index.d.ts +32 -0
- data/lib/feelin/js/node_modules/lezer-feel/dist/index.js +1323 -0
- data/lib/feelin/js/node_modules/lezer-feel/dist/index.js.map +1 -0
- data/lib/feelin/js/node_modules/lezer-feel/package.json +61 -0
- data/lib/feelin/js/node_modules/luxon/LICENSE.md +7 -0
- data/lib/feelin/js/node_modules/luxon/README.md +55 -0
- data/lib/feelin/js/node_modules/luxon/build/amd/luxon.js +8623 -0
- data/lib/feelin/js/node_modules/luxon/build/amd/luxon.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/build/cjs-browser/luxon.js +8621 -0
- data/lib/feelin/js/node_modules/luxon/build/cjs-browser/luxon.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/build/es6/luxon.js +8011 -0
- data/lib/feelin/js/node_modules/luxon/build/es6/luxon.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/build/global/luxon.js +8626 -0
- data/lib/feelin/js/node_modules/luxon/build/global/luxon.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/build/global/luxon.min.js +1 -0
- data/lib/feelin/js/node_modules/luxon/build/global/luxon.min.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/build/node/luxon.js +7679 -0
- data/lib/feelin/js/node_modules/luxon/build/node/luxon.js.map +1 -0
- data/lib/feelin/js/node_modules/luxon/package.json +87 -0
- data/lib/feelin/js/node_modules/luxon/src/datetime.js +2566 -0
- data/lib/feelin/js/node_modules/luxon/src/duration.js +990 -0
- data/lib/feelin/js/node_modules/luxon/src/errors.js +61 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/conversions.js +206 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/diff.js +95 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/digits.js +90 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/english.js +233 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/formats.js +176 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/formatter.js +409 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/invalid.js +14 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/locale.js +554 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/regexParser.js +335 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/tokenParser.js +505 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/util.js +316 -0
- data/lib/feelin/js/node_modules/luxon/src/impl/zoneUtil.js +34 -0
- data/lib/feelin/js/node_modules/luxon/src/info.js +205 -0
- data/lib/feelin/js/node_modules/luxon/src/interval.js +665 -0
- data/lib/feelin/js/node_modules/luxon/src/luxon.js +26 -0
- data/lib/feelin/js/node_modules/luxon/src/package.json +4 -0
- data/lib/feelin/js/node_modules/luxon/src/settings.js +180 -0
- data/lib/feelin/js/node_modules/luxon/src/zone.js +97 -0
- data/lib/feelin/js/node_modules/luxon/src/zones/IANAZone.js +231 -0
- data/lib/feelin/js/node_modules/luxon/src/zones/fixedOffsetZone.js +150 -0
- data/lib/feelin/js/node_modules/luxon/src/zones/invalidZone.js +53 -0
- data/lib/feelin/js/node_modules/luxon/src/zones/systemZone.js +61 -0
- data/lib/feelin/js/node_modules/min-dash/LICENSE +21 -0
- data/lib/feelin/js/node_modules/min-dash/README.md +38 -0
- data/lib/feelin/js/node_modules/min-dash/dist/array.d.ts +12 -0
- data/lib/feelin/js/node_modules/min-dash/dist/collection.d.ts +174 -0
- data/lib/feelin/js/node_modules/min-dash/dist/fn.d.ts +37 -0
- data/lib/feelin/js/node_modules/min-dash/dist/index.cjs +910 -0
- data/lib/feelin/js/node_modules/min-dash/dist/index.d.ts +5 -0
- data/lib/feelin/js/node_modules/min-dash/dist/index.esm.js +872 -0
- data/lib/feelin/js/node_modules/min-dash/dist/lang.d.ts +29 -0
- data/lib/feelin/js/node_modules/min-dash/dist/min-dash.js +916 -0
- data/lib/feelin/js/node_modules/min-dash/dist/min-dash.min.js +1 -0
- data/lib/feelin/js/node_modules/min-dash/dist/object.d.ts +112 -0
- data/lib/feelin/js/node_modules/min-dash/package.json +72 -0
- data/lib/feelin/js/package-lock.json +72 -0
- data/lib/feelin/js/package.json +5 -0
- data/lib/feelin/version.rb +3 -0
- data/lib/feelin.rb +63 -0
- data/spec/feelin/feelin_spec.rb +38 -0
- data/spec/spec_helper.rb +2 -0
- metadata +198 -0
@@ -0,0 +1,316 @@
|
|
1
|
+
/*
|
2
|
+
This is just a junk drawer, containing anything used across multiple classes.
|
3
|
+
Because Luxon is small(ish), this should stay small and we won't worry about splitting
|
4
|
+
it up into, say, parsingUtil.js and basicUtil.js and so on. But they are divided up by feature area.
|
5
|
+
*/
|
6
|
+
|
7
|
+
import { InvalidArgumentError } from "../errors.js";
|
8
|
+
import Settings from "../settings.js";
|
9
|
+
import { dayOfWeek, isoWeekdayToLocal } from "./conversions.js";
|
10
|
+
|
11
|
+
/**
|
12
|
+
* @private
|
13
|
+
*/
|
14
|
+
|
15
|
+
// TYPES
|
16
|
+
|
17
|
+
export function isUndefined(o) {
|
18
|
+
return typeof o === "undefined";
|
19
|
+
}
|
20
|
+
|
21
|
+
export function isNumber(o) {
|
22
|
+
return typeof o === "number";
|
23
|
+
}
|
24
|
+
|
25
|
+
export function isInteger(o) {
|
26
|
+
return typeof o === "number" && o % 1 === 0;
|
27
|
+
}
|
28
|
+
|
29
|
+
export function isString(o) {
|
30
|
+
return typeof o === "string";
|
31
|
+
}
|
32
|
+
|
33
|
+
export function isDate(o) {
|
34
|
+
return Object.prototype.toString.call(o) === "[object Date]";
|
35
|
+
}
|
36
|
+
|
37
|
+
// CAPABILITIES
|
38
|
+
|
39
|
+
export function hasRelative() {
|
40
|
+
try {
|
41
|
+
return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat;
|
42
|
+
} catch (e) {
|
43
|
+
return false;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
export function hasLocaleWeekInfo() {
|
48
|
+
try {
|
49
|
+
return (
|
50
|
+
typeof Intl !== "undefined" &&
|
51
|
+
!!Intl.Locale &&
|
52
|
+
("weekInfo" in Intl.Locale.prototype || "getWeekInfo" in Intl.Locale.prototype)
|
53
|
+
);
|
54
|
+
} catch (e) {
|
55
|
+
return false;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
// OBJECTS AND ARRAYS
|
60
|
+
|
61
|
+
export function maybeArray(thing) {
|
62
|
+
return Array.isArray(thing) ? thing : [thing];
|
63
|
+
}
|
64
|
+
|
65
|
+
export function bestBy(arr, by, compare) {
|
66
|
+
if (arr.length === 0) {
|
67
|
+
return undefined;
|
68
|
+
}
|
69
|
+
return arr.reduce((best, next) => {
|
70
|
+
const pair = [by(next), next];
|
71
|
+
if (!best) {
|
72
|
+
return pair;
|
73
|
+
} else if (compare(best[0], pair[0]) === best[0]) {
|
74
|
+
return best;
|
75
|
+
} else {
|
76
|
+
return pair;
|
77
|
+
}
|
78
|
+
}, null)[1];
|
79
|
+
}
|
80
|
+
|
81
|
+
export function pick(obj, keys) {
|
82
|
+
return keys.reduce((a, k) => {
|
83
|
+
a[k] = obj[k];
|
84
|
+
return a;
|
85
|
+
}, {});
|
86
|
+
}
|
87
|
+
|
88
|
+
export function hasOwnProperty(obj, prop) {
|
89
|
+
return Object.prototype.hasOwnProperty.call(obj, prop);
|
90
|
+
}
|
91
|
+
|
92
|
+
export function validateWeekSettings(settings) {
|
93
|
+
if (settings == null) {
|
94
|
+
return null;
|
95
|
+
} else if (typeof settings !== "object") {
|
96
|
+
throw new InvalidArgumentError("Week settings must be an object");
|
97
|
+
} else {
|
98
|
+
if (
|
99
|
+
!integerBetween(settings.firstDay, 1, 7) ||
|
100
|
+
!integerBetween(settings.minimalDays, 1, 7) ||
|
101
|
+
!Array.isArray(settings.weekend) ||
|
102
|
+
settings.weekend.some((v) => !integerBetween(v, 1, 7))
|
103
|
+
) {
|
104
|
+
throw new InvalidArgumentError("Invalid week settings");
|
105
|
+
}
|
106
|
+
return {
|
107
|
+
firstDay: settings.firstDay,
|
108
|
+
minimalDays: settings.minimalDays,
|
109
|
+
weekend: Array.from(settings.weekend),
|
110
|
+
};
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
// NUMBERS AND STRINGS
|
115
|
+
|
116
|
+
export function integerBetween(thing, bottom, top) {
|
117
|
+
return isInteger(thing) && thing >= bottom && thing <= top;
|
118
|
+
}
|
119
|
+
|
120
|
+
// x % n but takes the sign of n instead of x
|
121
|
+
export function floorMod(x, n) {
|
122
|
+
return x - n * Math.floor(x / n);
|
123
|
+
}
|
124
|
+
|
125
|
+
export function padStart(input, n = 2) {
|
126
|
+
const isNeg = input < 0;
|
127
|
+
let padded;
|
128
|
+
if (isNeg) {
|
129
|
+
padded = "-" + ("" + -input).padStart(n, "0");
|
130
|
+
} else {
|
131
|
+
padded = ("" + input).padStart(n, "0");
|
132
|
+
}
|
133
|
+
return padded;
|
134
|
+
}
|
135
|
+
|
136
|
+
export function parseInteger(string) {
|
137
|
+
if (isUndefined(string) || string === null || string === "") {
|
138
|
+
return undefined;
|
139
|
+
} else {
|
140
|
+
return parseInt(string, 10);
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
export function parseFloating(string) {
|
145
|
+
if (isUndefined(string) || string === null || string === "") {
|
146
|
+
return undefined;
|
147
|
+
} else {
|
148
|
+
return parseFloat(string);
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
export function parseMillis(fraction) {
|
153
|
+
// Return undefined (instead of 0) in these cases, where fraction is not set
|
154
|
+
if (isUndefined(fraction) || fraction === null || fraction === "") {
|
155
|
+
return undefined;
|
156
|
+
} else {
|
157
|
+
const f = parseFloat("0." + fraction) * 1000;
|
158
|
+
return Math.floor(f);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
export function roundTo(number, digits, towardZero = false) {
|
163
|
+
const factor = 10 ** digits,
|
164
|
+
rounder = towardZero ? Math.trunc : Math.round;
|
165
|
+
return rounder(number * factor) / factor;
|
166
|
+
}
|
167
|
+
|
168
|
+
// DATE BASICS
|
169
|
+
|
170
|
+
export function isLeapYear(year) {
|
171
|
+
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
172
|
+
}
|
173
|
+
|
174
|
+
export function daysInYear(year) {
|
175
|
+
return isLeapYear(year) ? 366 : 365;
|
176
|
+
}
|
177
|
+
|
178
|
+
export function daysInMonth(year, month) {
|
179
|
+
const modMonth = floorMod(month - 1, 12) + 1,
|
180
|
+
modYear = year + (month - modMonth) / 12;
|
181
|
+
|
182
|
+
if (modMonth === 2) {
|
183
|
+
return isLeapYear(modYear) ? 29 : 28;
|
184
|
+
} else {
|
185
|
+
return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1];
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
// convert a calendar object to a local timestamp (epoch, but with the offset baked in)
|
190
|
+
export function objToLocalTS(obj) {
|
191
|
+
let d = Date.UTC(
|
192
|
+
obj.year,
|
193
|
+
obj.month - 1,
|
194
|
+
obj.day,
|
195
|
+
obj.hour,
|
196
|
+
obj.minute,
|
197
|
+
obj.second,
|
198
|
+
obj.millisecond
|
199
|
+
);
|
200
|
+
|
201
|
+
// for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that
|
202
|
+
if (obj.year < 100 && obj.year >= 0) {
|
203
|
+
d = new Date(d);
|
204
|
+
// set the month and day again, this is necessary because year 2000 is a leap year, but year 100 is not
|
205
|
+
// so if obj.year is in 99, but obj.day makes it roll over into year 100,
|
206
|
+
// the calculations done by Date.UTC are using year 2000 - which is incorrect
|
207
|
+
d.setUTCFullYear(obj.year, obj.month - 1, obj.day);
|
208
|
+
}
|
209
|
+
return +d;
|
210
|
+
}
|
211
|
+
|
212
|
+
// adapted from moment.js: https://github.com/moment/moment/blob/000ac1800e620f770f4eb31b5ae908f6167b0ab2/src/lib/units/week-calendar-utils.js
|
213
|
+
function firstWeekOffset(year, minDaysInFirstWeek, startOfWeek) {
|
214
|
+
const fwdlw = isoWeekdayToLocal(dayOfWeek(year, 1, minDaysInFirstWeek), startOfWeek);
|
215
|
+
return -fwdlw + minDaysInFirstWeek - 1;
|
216
|
+
}
|
217
|
+
|
218
|
+
export function weeksInWeekYear(weekYear, minDaysInFirstWeek = 4, startOfWeek = 1) {
|
219
|
+
const weekOffset = firstWeekOffset(weekYear, minDaysInFirstWeek, startOfWeek);
|
220
|
+
const weekOffsetNext = firstWeekOffset(weekYear + 1, minDaysInFirstWeek, startOfWeek);
|
221
|
+
return (daysInYear(weekYear) - weekOffset + weekOffsetNext) / 7;
|
222
|
+
}
|
223
|
+
|
224
|
+
export function untruncateYear(year) {
|
225
|
+
if (year > 99) {
|
226
|
+
return year;
|
227
|
+
} else return year > Settings.twoDigitCutoffYear ? 1900 + year : 2000 + year;
|
228
|
+
}
|
229
|
+
|
230
|
+
// PARSING
|
231
|
+
|
232
|
+
export function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) {
|
233
|
+
const date = new Date(ts),
|
234
|
+
intlOpts = {
|
235
|
+
hourCycle: "h23",
|
236
|
+
year: "numeric",
|
237
|
+
month: "2-digit",
|
238
|
+
day: "2-digit",
|
239
|
+
hour: "2-digit",
|
240
|
+
minute: "2-digit",
|
241
|
+
};
|
242
|
+
|
243
|
+
if (timeZone) {
|
244
|
+
intlOpts.timeZone = timeZone;
|
245
|
+
}
|
246
|
+
|
247
|
+
const modified = { timeZoneName: offsetFormat, ...intlOpts };
|
248
|
+
|
249
|
+
const parsed = new Intl.DateTimeFormat(locale, modified)
|
250
|
+
.formatToParts(date)
|
251
|
+
.find((m) => m.type.toLowerCase() === "timezonename");
|
252
|
+
return parsed ? parsed.value : null;
|
253
|
+
}
|
254
|
+
|
255
|
+
// signedOffset('-5', '30') -> -330
|
256
|
+
export function signedOffset(offHourStr, offMinuteStr) {
|
257
|
+
let offHour = parseInt(offHourStr, 10);
|
258
|
+
|
259
|
+
// don't || this because we want to preserve -0
|
260
|
+
if (Number.isNaN(offHour)) {
|
261
|
+
offHour = 0;
|
262
|
+
}
|
263
|
+
|
264
|
+
const offMin = parseInt(offMinuteStr, 10) || 0,
|
265
|
+
offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin;
|
266
|
+
return offHour * 60 + offMinSigned;
|
267
|
+
}
|
268
|
+
|
269
|
+
// COERCION
|
270
|
+
|
271
|
+
export function asNumber(value) {
|
272
|
+
const numericValue = Number(value);
|
273
|
+
if (typeof value === "boolean" || value === "" || Number.isNaN(numericValue))
|
274
|
+
throw new InvalidArgumentError(`Invalid unit value ${value}`);
|
275
|
+
return numericValue;
|
276
|
+
}
|
277
|
+
|
278
|
+
export function normalizeObject(obj, normalizer) {
|
279
|
+
const normalized = {};
|
280
|
+
for (const u in obj) {
|
281
|
+
if (hasOwnProperty(obj, u)) {
|
282
|
+
const v = obj[u];
|
283
|
+
if (v === undefined || v === null) continue;
|
284
|
+
normalized[normalizer(u)] = asNumber(v);
|
285
|
+
}
|
286
|
+
}
|
287
|
+
return normalized;
|
288
|
+
}
|
289
|
+
|
290
|
+
/**
|
291
|
+
* Returns the offset's value as a string
|
292
|
+
* @param {number} ts - Epoch milliseconds for which to get the offset
|
293
|
+
* @param {string} format - What style of offset to return.
|
294
|
+
* Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively
|
295
|
+
* @return {string}
|
296
|
+
*/
|
297
|
+
export function formatOffset(offset, format) {
|
298
|
+
const hours = Math.trunc(Math.abs(offset / 60)),
|
299
|
+
minutes = Math.trunc(Math.abs(offset % 60)),
|
300
|
+
sign = offset >= 0 ? "+" : "-";
|
301
|
+
|
302
|
+
switch (format) {
|
303
|
+
case "short":
|
304
|
+
return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;
|
305
|
+
case "narrow":
|
306
|
+
return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`;
|
307
|
+
case "techie":
|
308
|
+
return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;
|
309
|
+
default:
|
310
|
+
throw new RangeError(`Value format ${format} is out of range for property format`);
|
311
|
+
}
|
312
|
+
}
|
313
|
+
|
314
|
+
export function timeObject(obj) {
|
315
|
+
return pick(obj, ["hour", "minute", "second", "millisecond"]);
|
316
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
/**
|
2
|
+
* @private
|
3
|
+
*/
|
4
|
+
|
5
|
+
import Zone from "../zone.js";
|
6
|
+
import IANAZone from "../zones/IANAZone.js";
|
7
|
+
import FixedOffsetZone from "../zones/fixedOffsetZone.js";
|
8
|
+
import InvalidZone from "../zones/invalidZone.js";
|
9
|
+
|
10
|
+
import { isUndefined, isString, isNumber } from "./util.js";
|
11
|
+
import SystemZone from "../zones/systemZone.js";
|
12
|
+
|
13
|
+
export function normalizeZone(input, defaultZone) {
|
14
|
+
let offset;
|
15
|
+
if (isUndefined(input) || input === null) {
|
16
|
+
return defaultZone;
|
17
|
+
} else if (input instanceof Zone) {
|
18
|
+
return input;
|
19
|
+
} else if (isString(input)) {
|
20
|
+
const lowered = input.toLowerCase();
|
21
|
+
if (lowered === "default") return defaultZone;
|
22
|
+
else if (lowered === "local" || lowered === "system") return SystemZone.instance;
|
23
|
+
else if (lowered === "utc" || lowered === "gmt") return FixedOffsetZone.utcInstance;
|
24
|
+
else return FixedOffsetZone.parseSpecifier(lowered) || IANAZone.create(input);
|
25
|
+
} else if (isNumber(input)) {
|
26
|
+
return FixedOffsetZone.instance(input);
|
27
|
+
} else if (typeof input === "object" && "offset" in input && typeof input.offset === "function") {
|
28
|
+
// This is dumb, but the instanceof check above doesn't seem to really work
|
29
|
+
// so we're duck checking it
|
30
|
+
return input;
|
31
|
+
} else {
|
32
|
+
return new InvalidZone(input);
|
33
|
+
}
|
34
|
+
}
|
@@ -0,0 +1,205 @@
|
|
1
|
+
import DateTime from "./datetime.js";
|
2
|
+
import Settings from "./settings.js";
|
3
|
+
import Locale from "./impl/locale.js";
|
4
|
+
import IANAZone from "./zones/IANAZone.js";
|
5
|
+
import { normalizeZone } from "./impl/zoneUtil.js";
|
6
|
+
|
7
|
+
import { hasLocaleWeekInfo, hasRelative } from "./impl/util.js";
|
8
|
+
|
9
|
+
/**
|
10
|
+
* The Info class contains static methods for retrieving general time and date related data. For example, it has methods for finding out if a time zone has a DST, for listing the months in any supported locale, and for discovering which of Luxon features are available in the current environment.
|
11
|
+
*/
|
12
|
+
export default class Info {
|
13
|
+
/**
|
14
|
+
* Return whether the specified zone contains a DST.
|
15
|
+
* @param {string|Zone} [zone='local'] - Zone to check. Defaults to the environment's local zone.
|
16
|
+
* @return {boolean}
|
17
|
+
*/
|
18
|
+
static hasDST(zone = Settings.defaultZone) {
|
19
|
+
const proto = DateTime.now().setZone(zone).set({ month: 12 });
|
20
|
+
|
21
|
+
return !zone.isUniversal && proto.offset !== proto.set({ month: 6 }).offset;
|
22
|
+
}
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Return whether the specified zone is a valid IANA specifier.
|
26
|
+
* @param {string} zone - Zone to check
|
27
|
+
* @return {boolean}
|
28
|
+
*/
|
29
|
+
static isValidIANAZone(zone) {
|
30
|
+
return IANAZone.isValidZone(zone);
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Converts the input into a {@link Zone} instance.
|
35
|
+
*
|
36
|
+
* * If `input` is already a Zone instance, it is returned unchanged.
|
37
|
+
* * If `input` is a string containing a valid time zone name, a Zone instance
|
38
|
+
* with that name is returned.
|
39
|
+
* * If `input` is a string that doesn't refer to a known time zone, a Zone
|
40
|
+
* instance with {@link Zone#isValid} == false is returned.
|
41
|
+
* * If `input is a number, a Zone instance with the specified fixed offset
|
42
|
+
* in minutes is returned.
|
43
|
+
* * If `input` is `null` or `undefined`, the default zone is returned.
|
44
|
+
* @param {string|Zone|number} [input] - the value to be converted
|
45
|
+
* @return {Zone}
|
46
|
+
*/
|
47
|
+
static normalizeZone(input) {
|
48
|
+
return normalizeZone(input, Settings.defaultZone);
|
49
|
+
}
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Get the weekday on which the week starts according to the given locale.
|
53
|
+
* @param {Object} opts - options
|
54
|
+
* @param {string} [opts.locale] - the locale code
|
55
|
+
* @param {string} [opts.locObj=null] - an existing locale object to use
|
56
|
+
* @returns {number} the start of the week, 1 for Monday through 7 for Sunday
|
57
|
+
*/
|
58
|
+
static getStartOfWeek({ locale = null, locObj = null } = {}) {
|
59
|
+
return (locObj || Locale.create(locale)).getStartOfWeek();
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Get the minimum number of days necessary in a week before it is considered part of the next year according
|
64
|
+
* to the given locale.
|
65
|
+
* @param {Object} opts - options
|
66
|
+
* @param {string} [opts.locale] - the locale code
|
67
|
+
* @param {string} [opts.locObj=null] - an existing locale object to use
|
68
|
+
* @returns {number}
|
69
|
+
*/
|
70
|
+
static getMinimumDaysInFirstWeek({ locale = null, locObj = null } = {}) {
|
71
|
+
return (locObj || Locale.create(locale)).getMinDaysInFirstWeek();
|
72
|
+
}
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Get the weekdays, which are considered the weekend according to the given locale
|
76
|
+
* @param {Object} opts - options
|
77
|
+
* @param {string} [opts.locale] - the locale code
|
78
|
+
* @param {string} [opts.locObj=null] - an existing locale object to use
|
79
|
+
* @returns {number[]} an array of weekdays, 1 for Monday through 7 for Sunday
|
80
|
+
*/
|
81
|
+
static getWeekendWeekdays({ locale = null, locObj = null } = {}) {
|
82
|
+
// copy the array, because we cache it internally
|
83
|
+
return (locObj || Locale.create(locale)).getWeekendDays().slice();
|
84
|
+
}
|
85
|
+
|
86
|
+
/**
|
87
|
+
* Return an array of standalone month names.
|
88
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
|
89
|
+
* @param {string} [length='long'] - the length of the month representation, such as "numeric", "2-digit", "narrow", "short", "long"
|
90
|
+
* @param {Object} opts - options
|
91
|
+
* @param {string} [opts.locale] - the locale code
|
92
|
+
* @param {string} [opts.numberingSystem=null] - the numbering system
|
93
|
+
* @param {string} [opts.locObj=null] - an existing locale object to use
|
94
|
+
* @param {string} [opts.outputCalendar='gregory'] - the calendar
|
95
|
+
* @example Info.months()[0] //=> 'January'
|
96
|
+
* @example Info.months('short')[0] //=> 'Jan'
|
97
|
+
* @example Info.months('numeric')[0] //=> '1'
|
98
|
+
* @example Info.months('short', { locale: 'fr-CA' } )[0] //=> 'janv.'
|
99
|
+
* @example Info.months('numeric', { locale: 'ar' })[0] //=> '١'
|
100
|
+
* @example Info.months('long', { outputCalendar: 'islamic' })[0] //=> 'Rabiʻ I'
|
101
|
+
* @return {Array}
|
102
|
+
*/
|
103
|
+
static months(
|
104
|
+
length = "long",
|
105
|
+
{ locale = null, numberingSystem = null, locObj = null, outputCalendar = "gregory" } = {}
|
106
|
+
) {
|
107
|
+
return (locObj || Locale.create(locale, numberingSystem, outputCalendar)).months(length);
|
108
|
+
}
|
109
|
+
|
110
|
+
/**
|
111
|
+
* Return an array of format month names.
|
112
|
+
* Format months differ from standalone months in that they're meant to appear next to the day of the month. In some languages, that
|
113
|
+
* changes the string.
|
114
|
+
* See {@link Info#months}
|
115
|
+
* @param {string} [length='long'] - the length of the month representation, such as "numeric", "2-digit", "narrow", "short", "long"
|
116
|
+
* @param {Object} opts - options
|
117
|
+
* @param {string} [opts.locale] - the locale code
|
118
|
+
* @param {string} [opts.numberingSystem=null] - the numbering system
|
119
|
+
* @param {string} [opts.locObj=null] - an existing locale object to use
|
120
|
+
* @param {string} [opts.outputCalendar='gregory'] - the calendar
|
121
|
+
* @return {Array}
|
122
|
+
*/
|
123
|
+
static monthsFormat(
|
124
|
+
length = "long",
|
125
|
+
{ locale = null, numberingSystem = null, locObj = null, outputCalendar = "gregory" } = {}
|
126
|
+
) {
|
127
|
+
return (locObj || Locale.create(locale, numberingSystem, outputCalendar)).months(length, true);
|
128
|
+
}
|
129
|
+
|
130
|
+
/**
|
131
|
+
* Return an array of standalone week names.
|
132
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
|
133
|
+
* @param {string} [length='long'] - the length of the weekday representation, such as "narrow", "short", "long".
|
134
|
+
* @param {Object} opts - options
|
135
|
+
* @param {string} [opts.locale] - the locale code
|
136
|
+
* @param {string} [opts.numberingSystem=null] - the numbering system
|
137
|
+
* @param {string} [opts.locObj=null] - an existing locale object to use
|
138
|
+
* @example Info.weekdays()[0] //=> 'Monday'
|
139
|
+
* @example Info.weekdays('short')[0] //=> 'Mon'
|
140
|
+
* @example Info.weekdays('short', { locale: 'fr-CA' })[0] //=> 'lun.'
|
141
|
+
* @example Info.weekdays('short', { locale: 'ar' })[0] //=> 'الاثنين'
|
142
|
+
* @return {Array}
|
143
|
+
*/
|
144
|
+
static weekdays(length = "long", { locale = null, numberingSystem = null, locObj = null } = {}) {
|
145
|
+
return (locObj || Locale.create(locale, numberingSystem, null)).weekdays(length);
|
146
|
+
}
|
147
|
+
|
148
|
+
/**
|
149
|
+
* Return an array of format week names.
|
150
|
+
* Format weekdays differ from standalone weekdays in that they're meant to appear next to more date information. In some languages, that
|
151
|
+
* changes the string.
|
152
|
+
* See {@link Info#weekdays}
|
153
|
+
* @param {string} [length='long'] - the length of the month representation, such as "narrow", "short", "long".
|
154
|
+
* @param {Object} opts - options
|
155
|
+
* @param {string} [opts.locale=null] - the locale code
|
156
|
+
* @param {string} [opts.numberingSystem=null] - the numbering system
|
157
|
+
* @param {string} [opts.locObj=null] - an existing locale object to use
|
158
|
+
* @return {Array}
|
159
|
+
*/
|
160
|
+
static weekdaysFormat(
|
161
|
+
length = "long",
|
162
|
+
{ locale = null, numberingSystem = null, locObj = null } = {}
|
163
|
+
) {
|
164
|
+
return (locObj || Locale.create(locale, numberingSystem, null)).weekdays(length, true);
|
165
|
+
}
|
166
|
+
|
167
|
+
/**
|
168
|
+
* Return an array of meridiems.
|
169
|
+
* @param {Object} opts - options
|
170
|
+
* @param {string} [opts.locale] - the locale code
|
171
|
+
* @example Info.meridiems() //=> [ 'AM', 'PM' ]
|
172
|
+
* @example Info.meridiems({ locale: 'my' }) //=> [ 'နံနက်', 'ညနေ' ]
|
173
|
+
* @return {Array}
|
174
|
+
*/
|
175
|
+
static meridiems({ locale = null } = {}) {
|
176
|
+
return Locale.create(locale).meridiems();
|
177
|
+
}
|
178
|
+
|
179
|
+
/**
|
180
|
+
* Return an array of eras, such as ['BC', 'AD']. The locale can be specified, but the calendar system is always Gregorian.
|
181
|
+
* @param {string} [length='short'] - the length of the era representation, such as "short" or "long".
|
182
|
+
* @param {Object} opts - options
|
183
|
+
* @param {string} [opts.locale] - the locale code
|
184
|
+
* @example Info.eras() //=> [ 'BC', 'AD' ]
|
185
|
+
* @example Info.eras('long') //=> [ 'Before Christ', 'Anno Domini' ]
|
186
|
+
* @example Info.eras('long', { locale: 'fr' }) //=> [ 'avant Jésus-Christ', 'après Jésus-Christ' ]
|
187
|
+
* @return {Array}
|
188
|
+
*/
|
189
|
+
static eras(length = "short", { locale = null } = {}) {
|
190
|
+
return Locale.create(locale, null, "gregory").eras(length);
|
191
|
+
}
|
192
|
+
|
193
|
+
/**
|
194
|
+
* Return the set of available features in this environment.
|
195
|
+
* Some features of Luxon are not available in all environments. For example, on older browsers, relative time formatting support is not available. Use this function to figure out if that's the case.
|
196
|
+
* Keys:
|
197
|
+
* * `relative`: whether this environment supports relative time formatting
|
198
|
+
* * `localeWeek`: whether this environment supports different weekdays for the start of the week based on the locale
|
199
|
+
* @example Info.features() //=> { relative: false, localeWeek: true }
|
200
|
+
* @return {Object}
|
201
|
+
*/
|
202
|
+
static features() {
|
203
|
+
return { relative: hasRelative(), localeWeek: hasLocaleWeekInfo() };
|
204
|
+
}
|
205
|
+
}
|