chrono-node 2.6.1 → 2.6.3
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/README.md +32 -2
- package/dist/cjs/common/refiners/AbstractMergeDateRangeRefiner.js +15 -7
- package/dist/cjs/common/refiners/AbstractMergeDateRangeRefiner.js.map +1 -1
- package/dist/cjs/common/refiners/ExtractTimezoneAbbrRefiner.d.ts +3 -4
- package/dist/cjs/common/refiners/ExtractTimezoneAbbrRefiner.js +6 -196
- package/dist/cjs/common/refiners/ExtractTimezoneAbbrRefiner.js.map +1 -1
- package/dist/cjs/common/refiners/ForwardDateRefiner.js +14 -14
- package/dist/cjs/common/refiners/ForwardDateRefiner.js.map +1 -1
- package/dist/cjs/configurations.js +1 -1
- package/dist/cjs/configurations.js.map +1 -1
- package/dist/cjs/index.d.ts +26 -4
- package/dist/cjs/index.js +16 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/locales/en/constants.d.ts +4 -0
- package/dist/cjs/locales/en/constants.js +5 -18
- package/dist/cjs/locales/en/constants.js.map +1 -1
- package/dist/cjs/locales/en/index.js +1 -1
- package/dist/cjs/locales/en/index.js.map +1 -1
- package/dist/cjs/locales/en/parsers/ENMonthNameMiddleEndianParser.d.ts +1 -1
- package/dist/cjs/locales/en/parsers/ENMonthNameParser.d.ts +1 -1
- package/dist/cjs/locales/en/parsers/ENTimeUnitAgoFormatParser.js +2 -2
- package/dist/cjs/locales/en/parsers/ENTimeUnitAgoFormatParser.js.map +1 -1
- package/dist/cjs/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.d.ts +2 -0
- package/dist/cjs/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.js +6 -1
- package/dist/cjs/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.js.map +1 -1
- package/dist/cjs/locales/en/parsers/ENTimeUnitLaterFormatParser.js +1 -1
- package/dist/cjs/locales/en/parsers/ENTimeUnitLaterFormatParser.js.map +1 -1
- package/dist/cjs/locales/en/parsers/ENTimeUnitWithinFormatParser.d.ts +2 -0
- package/dist/cjs/locales/en/parsers/ENTimeUnitWithinFormatParser.js +10 -1
- package/dist/cjs/locales/en/parsers/ENTimeUnitWithinFormatParser.js.map +1 -1
- package/dist/cjs/locales/nl/parsers/NLMonthNameMiddleEndianParser.d.ts +1 -1
- package/dist/cjs/locales/ru/constants.js +4 -1
- package/dist/cjs/locales/ru/constants.js.map +1 -1
- package/dist/cjs/locales/ru/parsers/RUMonthNameParser.d.ts +1 -1
- package/dist/cjs/locales/zh/hans/parsers/ZHHansDateParser.d.ts +1 -1
- package/dist/cjs/locales/zh/hans/parsers/ZHHansDeadlineFormatParser.d.ts +1 -1
- package/dist/cjs/locales/zh/hans/parsers/ZHHansTimeExpressionParser.d.ts +1 -1
- package/dist/cjs/locales/zh/hant/parsers/ZHHantDateParser.d.ts +1 -1
- package/dist/cjs/locales/zh/hant/parsers/ZHHantDeadlineFormatParser.d.ts +1 -1
- package/dist/cjs/locales/zh/hant/parsers/ZHHantTimeExpressionParser.d.ts +1 -1
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/results.d.ts +1 -1
- package/dist/cjs/results.js +3 -3
- package/dist/cjs/results.js.map +1 -1
- package/dist/cjs/timezone.d.ts +5 -194
- package/dist/cjs/timezone.js +80 -7
- package/dist/cjs/timezone.js.map +1 -1
- package/dist/esm/common/refiners/AbstractMergeDateRangeRefiner.js +15 -7
- package/dist/esm/common/refiners/AbstractMergeDateRangeRefiner.js.map +1 -1
- package/dist/esm/common/refiners/ExtractTimezoneAbbrRefiner.d.ts +3 -4
- package/dist/esm/common/refiners/ExtractTimezoneAbbrRefiner.js +6 -196
- package/dist/esm/common/refiners/ExtractTimezoneAbbrRefiner.js.map +1 -1
- package/dist/esm/common/refiners/ForwardDateRefiner.js +14 -14
- package/dist/esm/common/refiners/ForwardDateRefiner.js.map +1 -1
- package/dist/esm/configurations.js +1 -1
- package/dist/esm/configurations.js.map +1 -1
- package/dist/esm/index.d.ts +26 -4
- package/dist/esm/index.js +15 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/locales/en/constants.d.ts +4 -0
- package/dist/esm/locales/en/constants.js +21 -0
- package/dist/esm/locales/en/constants.js.map +1 -1
- package/dist/esm/locales/en/index.js +1 -1
- package/dist/esm/locales/en/index.js.map +1 -1
- package/dist/esm/locales/en/parsers/ENMonthNameMiddleEndianParser.d.ts +1 -1
- package/dist/esm/locales/en/parsers/ENMonthNameParser.d.ts +1 -1
- package/dist/esm/locales/en/parsers/ENTimeUnitAgoFormatParser.js +3 -3
- package/dist/esm/locales/en/parsers/ENTimeUnitAgoFormatParser.js.map +1 -1
- package/dist/esm/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.d.ts +2 -0
- package/dist/esm/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.js +7 -2
- package/dist/esm/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.js.map +1 -1
- package/dist/esm/locales/en/parsers/ENTimeUnitLaterFormatParser.js +2 -2
- package/dist/esm/locales/en/parsers/ENTimeUnitLaterFormatParser.js.map +1 -1
- package/dist/esm/locales/en/parsers/ENTimeUnitWithinFormatParser.d.ts +2 -0
- package/dist/esm/locales/en/parsers/ENTimeUnitWithinFormatParser.js +11 -2
- package/dist/esm/locales/en/parsers/ENTimeUnitWithinFormatParser.js.map +1 -1
- package/dist/esm/locales/nl/parsers/NLMonthNameMiddleEndianParser.d.ts +1 -1
- package/dist/esm/locales/ru/constants.js +4 -1
- package/dist/esm/locales/ru/constants.js.map +1 -1
- package/dist/esm/locales/ru/parsers/RUMonthNameParser.d.ts +1 -1
- package/dist/esm/locales/zh/hans/parsers/ZHHansDateParser.d.ts +1 -1
- package/dist/esm/locales/zh/hans/parsers/ZHHansDeadlineFormatParser.d.ts +1 -1
- package/dist/esm/locales/zh/hans/parsers/ZHHansTimeExpressionParser.d.ts +1 -1
- package/dist/esm/locales/zh/hant/parsers/ZHHantDateParser.d.ts +1 -1
- package/dist/esm/locales/zh/hant/parsers/ZHHantDeadlineFormatParser.d.ts +1 -1
- package/dist/esm/locales/zh/hant/parsers/ZHHantTimeExpressionParser.d.ts +1 -1
- package/dist/esm/package.json +1 -1
- package/dist/esm/results.d.ts +1 -1
- package/dist/esm/results.js +3 -3
- package/dist/esm/results.js.map +1 -1
- package/dist/esm/timezone.d.ts +5 -194
- package/dist/esm/timezone.js +74 -6
- package/dist/esm/timezone.js.map +1 -1
- package/package.json +6 -7
- package/src/common/refiners/AbstractMergeDateRangeRefiner.ts +13 -8
- package/src/common/refiners/ExtractTimezoneAbbrRefiner.ts +7 -201
- package/src/common/refiners/ForwardDateRefiner.ts +18 -16
- package/src/configurations.ts +3 -1
- package/src/index.ts +48 -3
- package/src/locales/en/constants.ts +30 -0
- package/src/locales/en/index.ts +1 -1
- package/src/locales/en/parsers/ENTimeUnitAgoFormatParser.ts +3 -3
- package/src/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.ts +10 -2
- package/src/locales/en/parsers/ENTimeUnitLaterFormatParser.ts +5 -2
- package/src/locales/en/parsers/ENTimeUnitWithinFormatParser.ts +16 -3
- package/src/locales/ru/constants.ts +4 -1
- package/src/results.ts +3 -3
- package/src/timezone.ts +124 -7
- package/test/de/de_time_exp.test.ts +7 -7
- package/test/en/en_month.test.ts +70 -0
- package/test/en/en_time_units_ago.test.ts +12 -0
- package/test/en/en_time_units_casual_relative.test.ts +18 -0
- package/test/en/en_time_units_later.test.ts +13 -10
- package/test/en/en_time_units_within.test.ts +12 -1
- package/test/en/en_timezone_exp.test.ts +142 -0
- package/test/en/en_weekday.test.ts +26 -0
- package/test/en/negative_cases.test.ts +2 -0
- package/test/fr/fr_time_exp.test.ts +2 -2
- package/test/system.test.ts +23 -1
|
@@ -30,22 +30,6 @@ export default class ForwardDateRefiner implements Refiner {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
if (result.start.isOnlyDayMonthComponent() && refMoment.isAfter(result.start.dayjs())) {
|
|
34
|
-
for (let i = 0; i < 3 && refMoment.isAfter(result.start.dayjs()); i++) {
|
|
35
|
-
result.start.imply("year", result.start.get("year") + 1);
|
|
36
|
-
context.debug(() => {
|
|
37
|
-
console.log(`Forward yearly adjusted for ${result} (${result.start})`);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
if (result.end && !result.end.isCertain("year")) {
|
|
41
|
-
result.end.imply("year", result.end.get("year") + 1);
|
|
42
|
-
context.debug(() => {
|
|
43
|
-
console.log(`Forward yearly adjusted for ${result} (${result.end})`);
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
33
|
if (result.start.isOnlyWeekdayComponent() && refMoment.isAfter(result.start.dayjs())) {
|
|
50
34
|
if (refMoment.day() >= result.start.get("weekday")) {
|
|
51
35
|
refMoment = refMoment.day(result.start.get("weekday") + 7);
|
|
@@ -76,6 +60,24 @@ export default class ForwardDateRefiner implements Refiner {
|
|
|
76
60
|
});
|
|
77
61
|
}
|
|
78
62
|
}
|
|
63
|
+
|
|
64
|
+
// In case where we know the month, but not which year (e.g. "in December", "25th December"),
|
|
65
|
+
// try move to another year
|
|
66
|
+
if (result.start.isDateWithUnknownYear() && refMoment.isAfter(result.start.dayjs())) {
|
|
67
|
+
for (let i = 0; i < 3 && refMoment.isAfter(result.start.dayjs()); i++) {
|
|
68
|
+
result.start.imply("year", result.start.get("year") + 1);
|
|
69
|
+
context.debug(() => {
|
|
70
|
+
console.log(`Forward yearly adjusted for ${result} (${result.start})`);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (result.end && !result.end.isCertain("year")) {
|
|
74
|
+
result.end.imply("year", result.end.get("year") + 1);
|
|
75
|
+
context.debug(() => {
|
|
76
|
+
console.log(`Forward yearly adjusted for ${result} (${result.end})`);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
79
81
|
});
|
|
80
82
|
|
|
81
83
|
return results;
|
package/src/configurations.ts
CHANGED
|
@@ -12,10 +12,12 @@ export function includeCommonConfiguration(configuration: Configuration, strictM
|
|
|
12
12
|
configuration.parsers.unshift(new ISOFormatParser());
|
|
13
13
|
|
|
14
14
|
configuration.refiners.unshift(new MergeWeekdayComponentRefiner());
|
|
15
|
-
configuration.refiners.unshift(new ExtractTimezoneAbbrRefiner());
|
|
16
15
|
configuration.refiners.unshift(new ExtractTimezoneOffsetRefiner());
|
|
17
16
|
configuration.refiners.unshift(new OverlapRemovalRefiner());
|
|
18
17
|
|
|
18
|
+
// Unlike ExtractTimezoneOffsetRefiner, this refiner relies on knowing both date and time in cases where the tz
|
|
19
|
+
// is ambiguous (in terms of DST/non-DST). It therefore needs to be applied as late as possible in the parsing.
|
|
20
|
+
configuration.refiners.push(new ExtractTimezoneAbbrRefiner());
|
|
19
21
|
configuration.refiners.push(new OverlapRemovalRefiner());
|
|
20
22
|
configuration.refiners.push(new ForwardDateRefiner());
|
|
21
23
|
configuration.refiners.push(new UnlikelyFormatFilter(strictMode));
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { DebugHandler, DebugConsume } from "./debugging";
|
|
2
2
|
import * as en from "./locales/en";
|
|
3
3
|
import { Chrono, Parser, Refiner } from "./chrono";
|
|
4
|
+
import type { ParsingResult } from "./results";
|
|
4
5
|
|
|
5
|
-
export { en, Chrono, Parser, Refiner };
|
|
6
|
+
export { en, Chrono, Parser, Refiner, ParsingResult };
|
|
6
7
|
|
|
7
8
|
export interface ParsingOption {
|
|
8
9
|
/**
|
|
@@ -12,9 +13,10 @@ export interface ParsingOption {
|
|
|
12
13
|
forwardDate?: boolean;
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
|
-
* Additional timezone keywords for the parsers to recognize
|
|
16
|
+
* Additional timezone keywords for the parsers to recognize.
|
|
17
|
+
* Any value provided will override the default handling of that value.
|
|
16
18
|
*/
|
|
17
|
-
timezones?:
|
|
19
|
+
timezones?: TimezoneAbbrMap;
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* Internal debug event handler.
|
|
@@ -23,6 +25,34 @@ export interface ParsingOption {
|
|
|
23
25
|
debug?: DebugHandler | DebugConsume;
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Some timezone abbreviations are ambiguous in that they refer to different offsets
|
|
30
|
+
* depending on the time of year — daylight savings time (DST), or non-DST. This interface
|
|
31
|
+
* allows defining such timezones
|
|
32
|
+
*/
|
|
33
|
+
export interface AmbiguousTimezoneMap {
|
|
34
|
+
timezoneOffsetDuringDst: number;
|
|
35
|
+
timezoneOffsetNonDst: number;
|
|
36
|
+
/**
|
|
37
|
+
* Return the start date of DST for the given year.
|
|
38
|
+
* timezone.ts contains helper methods for common such rules.
|
|
39
|
+
*/
|
|
40
|
+
dstStart: (year: number) => Date;
|
|
41
|
+
/**
|
|
42
|
+
* Return the end date of DST for the given year.
|
|
43
|
+
* timezone.ts contains helper methods for common such rules.
|
|
44
|
+
*/
|
|
45
|
+
dstEnd: (year: number) => Date;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A map describing how timezone abbreviations should map to time offsets.
|
|
50
|
+
* Supports both unambigous mappings abbreviation => offset,
|
|
51
|
+
* and ambiguous mappings, where the offset will depend on whether the
|
|
52
|
+
* time in question is during daylight savings time or not.
|
|
53
|
+
*/
|
|
54
|
+
export type TimezoneAbbrMap = { [key: string]: number | AmbiguousTimezoneMap };
|
|
55
|
+
|
|
26
56
|
export interface ParsingReference {
|
|
27
57
|
/**
|
|
28
58
|
* Reference date. The instant (JavaScript Date object) when the input is written or mention.
|
|
@@ -109,6 +139,21 @@ export enum Weekday {
|
|
|
109
139
|
SATURDAY = 6,
|
|
110
140
|
}
|
|
111
141
|
|
|
142
|
+
export enum Month {
|
|
143
|
+
JANUARY = 1,
|
|
144
|
+
FEBRUARY = 2,
|
|
145
|
+
MARCH = 3,
|
|
146
|
+
APRIL = 4,
|
|
147
|
+
MAY = 5,
|
|
148
|
+
JUNE = 6,
|
|
149
|
+
JULY = 7,
|
|
150
|
+
AUGUST = 8,
|
|
151
|
+
SEPTEMBER = 9,
|
|
152
|
+
OCTOBER = 10,
|
|
153
|
+
NOVEMBER = 11,
|
|
154
|
+
DECEMBER = 12,
|
|
155
|
+
}
|
|
156
|
+
|
|
112
157
|
// Export all locales
|
|
113
158
|
import * as de from "./locales/de";
|
|
114
159
|
import * as fr from "./locales/fr";
|
|
@@ -134,6 +134,25 @@ export const ORDINAL_WORD_DICTIONARY: { [word: string]: number } = {
|
|
|
134
134
|
"thirty-first": 31,
|
|
135
135
|
};
|
|
136
136
|
|
|
137
|
+
export const TIME_UNIT_DICTIONARY_NO_ABBR: { [word: string]: OpUnitType | QUnitType } = {
|
|
138
|
+
second: "second",
|
|
139
|
+
seconds: "second",
|
|
140
|
+
minute: "minute",
|
|
141
|
+
minutes: "minute",
|
|
142
|
+
hour: "hour",
|
|
143
|
+
hours: "hour",
|
|
144
|
+
day: "d",
|
|
145
|
+
days: "d",
|
|
146
|
+
week: "week",
|
|
147
|
+
weeks: "week",
|
|
148
|
+
month: "month",
|
|
149
|
+
months: "month",
|
|
150
|
+
quarter: "quarter",
|
|
151
|
+
quarters: "quarter",
|
|
152
|
+
year: "year",
|
|
153
|
+
years: "year",
|
|
154
|
+
};
|
|
155
|
+
|
|
137
156
|
export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType | QUnitType } = {
|
|
138
157
|
s: "second",
|
|
139
158
|
sec: "second",
|
|
@@ -167,6 +186,9 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType | QUnitType } =
|
|
|
167
186
|
yr: "year",
|
|
168
187
|
year: "year",
|
|
169
188
|
years: "year",
|
|
189
|
+
// Also, merge the entries from the full-name dictionary.
|
|
190
|
+
// We leave the duplicated entries for readability.
|
|
191
|
+
...TIME_UNIT_DICTIONARY_NO_ABBR,
|
|
170
192
|
};
|
|
171
193
|
|
|
172
194
|
//-----------------------------
|
|
@@ -238,7 +260,15 @@ export function parseYear(match: string): number {
|
|
|
238
260
|
const SINGLE_TIME_UNIT_PATTERN = `(${NUMBER_PATTERN})\\s{0,3}(${matchAnyPattern(TIME_UNIT_DICTIONARY)})`;
|
|
239
261
|
const SINGLE_TIME_UNIT_REGEX = new RegExp(SINGLE_TIME_UNIT_PATTERN, "i");
|
|
240
262
|
|
|
263
|
+
const SINGLE_TIME_UNIT_NO_ABBR_PATTERN = `(${NUMBER_PATTERN})\\s{0,3}(${matchAnyPattern(
|
|
264
|
+
TIME_UNIT_DICTIONARY_NO_ABBR
|
|
265
|
+
)})`;
|
|
266
|
+
|
|
241
267
|
export const TIME_UNITS_PATTERN = repeatedTimeunitPattern(`(?:(?:about|around)\\s{0,3})?`, SINGLE_TIME_UNIT_PATTERN);
|
|
268
|
+
export const TIME_UNITS_NO_ABBR_PATTERN = repeatedTimeunitPattern(
|
|
269
|
+
`(?:(?:about|around)\\s{0,3})?`,
|
|
270
|
+
SINGLE_TIME_UNIT_NO_ABBR_PATTERN
|
|
271
|
+
);
|
|
242
272
|
|
|
243
273
|
export function parseTimeUnits(timeunitText): TimeUnits {
|
|
244
274
|
const fragments = {};
|
package/src/locales/en/index.ts
CHANGED
|
@@ -82,7 +82,7 @@ export function createConfiguration(strictMode = true, littleEndian = false): Co
|
|
|
82
82
|
{
|
|
83
83
|
parsers: [
|
|
84
84
|
new SlashDateFormatParser(littleEndian),
|
|
85
|
-
new ENTimeUnitWithinFormatParser(),
|
|
85
|
+
new ENTimeUnitWithinFormatParser(strictMode),
|
|
86
86
|
new ENMonthNameLittleEndianParser(),
|
|
87
87
|
new ENMonthNameMiddleEndianParser(),
|
|
88
88
|
new ENWeekdayParser(),
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ParsingContext } from "../../../chrono";
|
|
2
|
-
import { parseTimeUnits, TIME_UNITS_PATTERN } from "../constants";
|
|
2
|
+
import { parseTimeUnits, TIME_UNITS_NO_ABBR_PATTERN, TIME_UNITS_PATTERN } from "../constants";
|
|
3
3
|
import { ParsingComponents } from "../../../results";
|
|
4
4
|
import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary";
|
|
5
5
|
import { reverseTimeUnits } from "../../../utils/timeunits";
|
|
6
6
|
|
|
7
|
-
const PATTERN = new RegExp(`(${TIME_UNITS_PATTERN})\\s{0,5}(?:ago|before|earlier)(
|
|
8
|
-
const STRICT_PATTERN = new RegExp(`(${
|
|
7
|
+
const PATTERN = new RegExp(`(${TIME_UNITS_PATTERN})\\s{0,5}(?:ago|before|earlier)(?=\\W|$)`, "i");
|
|
8
|
+
const STRICT_PATTERN = new RegExp(`(${TIME_UNITS_NO_ABBR_PATTERN})\\s{0,5}(?:ago|before|earlier)(?=\\W|$)`, "i");
|
|
9
9
|
|
|
10
10
|
export default class ENTimeUnitAgoFormatParser extends AbstractParserWithWordBoundaryChecking {
|
|
11
11
|
constructor(private strictMode: boolean) {
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import { TIME_UNITS_PATTERN, parseTimeUnits } from "../constants";
|
|
1
|
+
import { TIME_UNITS_PATTERN, parseTimeUnits, TIME_UNITS_NO_ABBR_PATTERN } from "../constants";
|
|
2
2
|
import { ParsingContext } from "../../../chrono";
|
|
3
3
|
import { ParsingComponents } from "../../../results";
|
|
4
4
|
import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary";
|
|
5
5
|
import { reverseTimeUnits } from "../../../utils/timeunits";
|
|
6
6
|
|
|
7
7
|
const PATTERN = new RegExp(`(this|last|past|next|after|\\+|-)\\s*(${TIME_UNITS_PATTERN})(?=\\W|$)`, "i");
|
|
8
|
+
const PATTERN_NO_ABBR = new RegExp(
|
|
9
|
+
`(this|last|past|next|after|\\+|-)\\s*(${TIME_UNITS_NO_ABBR_PATTERN})(?=\\W|$)`,
|
|
10
|
+
"i"
|
|
11
|
+
);
|
|
8
12
|
|
|
9
13
|
export default class ENTimeUnitCasualRelativeFormatParser extends AbstractParserWithWordBoundaryChecking {
|
|
14
|
+
constructor(private allowAbbreviations: boolean = true) {
|
|
15
|
+
super();
|
|
16
|
+
}
|
|
17
|
+
|
|
10
18
|
innerPattern(): RegExp {
|
|
11
|
-
return PATTERN;
|
|
19
|
+
return this.allowAbbreviations ? PATTERN : PATTERN_NO_ABBR;
|
|
12
20
|
}
|
|
13
21
|
|
|
14
22
|
innerExtract(context: ParsingContext, match: RegExpMatchArray): ParsingComponents {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ParsingContext } from "../../../chrono";
|
|
2
|
-
import { parseTimeUnits, TIME_UNITS_PATTERN } from "../constants";
|
|
2
|
+
import { parseTimeUnits, TIME_UNITS_NO_ABBR_PATTERN, TIME_UNITS_PATTERN } from "../constants";
|
|
3
3
|
import { ParsingComponents } from "../../../results";
|
|
4
4
|
import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary";
|
|
5
5
|
|
|
@@ -8,7 +8,10 @@ const PATTERN = new RegExp(
|
|
|
8
8
|
"i"
|
|
9
9
|
);
|
|
10
10
|
|
|
11
|
-
const STRICT_PATTERN = new RegExp(
|
|
11
|
+
const STRICT_PATTERN = new RegExp(
|
|
12
|
+
"" + "(" + TIME_UNITS_NO_ABBR_PATTERN + ")" + "(later|from now)" + "(?=(?:\\W|$))",
|
|
13
|
+
"i"
|
|
14
|
+
);
|
|
12
15
|
const GROUP_NUM_TIMEUNITS = 1;
|
|
13
16
|
|
|
14
17
|
export default class ENTimeUnitLaterFormatParser extends AbstractParserWithWordBoundaryChecking {
|
|
@@ -1,21 +1,34 @@
|
|
|
1
|
-
import { TIME_UNITS_PATTERN, parseTimeUnits } from "../constants";
|
|
1
|
+
import { TIME_UNITS_PATTERN, parseTimeUnits, TIME_UNITS_NO_ABBR_PATTERN } from "../constants";
|
|
2
2
|
import { ParsingContext } from "../../../chrono";
|
|
3
3
|
import { ParsingComponents } from "../../../results";
|
|
4
4
|
import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary";
|
|
5
5
|
|
|
6
|
+
const PATTERN_WITHOUT_PREFIX = new RegExp(
|
|
7
|
+
`(?:(?:about|around|roughly|approximately|just)\\s*(?:~\\s*)?)?(${TIME_UNITS_PATTERN})(?=\\W|$)`,
|
|
8
|
+
"i"
|
|
9
|
+
);
|
|
10
|
+
|
|
6
11
|
const PATTERN_WITH_PREFIX = new RegExp(
|
|
7
12
|
`(?:within|in|for)\\s*` +
|
|
8
13
|
`(?:(?:about|around|roughly|approximately|just)\\s*(?:~\\s*)?)?(${TIME_UNITS_PATTERN})(?=\\W|$)`,
|
|
9
14
|
"i"
|
|
10
15
|
);
|
|
11
16
|
|
|
12
|
-
const
|
|
13
|
-
`(?:
|
|
17
|
+
const PATTERN_WITH_PREFIX_STRICT = new RegExp(
|
|
18
|
+
`(?:within|in|for)\\s*` +
|
|
19
|
+
`(?:(?:about|around|roughly|approximately|just)\\s*(?:~\\s*)?)?(${TIME_UNITS_NO_ABBR_PATTERN})(?=\\W|$)`,
|
|
14
20
|
"i"
|
|
15
21
|
);
|
|
16
22
|
|
|
17
23
|
export default class ENTimeUnitWithinFormatParser extends AbstractParserWithWordBoundaryChecking {
|
|
24
|
+
constructor(private strictMode: boolean) {
|
|
25
|
+
super();
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
innerPattern(context: ParsingContext): RegExp {
|
|
29
|
+
if (this.strictMode) {
|
|
30
|
+
return PATTERN_WITH_PREFIX_STRICT;
|
|
31
|
+
}
|
|
19
32
|
return context.option.forwardDate ? PATTERN_WITHOUT_PREFIX : PATTERN_WITH_PREFIX;
|
|
20
33
|
}
|
|
21
34
|
|
|
@@ -219,6 +219,9 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType | QUnitType } =
|
|
|
219
219
|
минуток: "minute",
|
|
220
220
|
минутки: "minute",
|
|
221
221
|
минутку: "minute",
|
|
222
|
+
минуточек: "minute",
|
|
223
|
+
минуточки: "minute",
|
|
224
|
+
минуточку: "minute",
|
|
222
225
|
час: "hour",
|
|
223
226
|
часов: "hour",
|
|
224
227
|
часа: "hour",
|
|
@@ -284,7 +287,7 @@ export function parseNumberPattern(match: string): number {
|
|
|
284
287
|
|
|
285
288
|
export const ORDINAL_NUMBER_PATTERN = `(?:${matchAnyPattern(ORDINAL_WORD_DICTIONARY)}|[0-9]{1,2}(?:го|ого|е|ое)?)`;
|
|
286
289
|
export function parseOrdinalNumberPattern(match: string): number {
|
|
287
|
-
|
|
290
|
+
const num = match.toLowerCase();
|
|
288
291
|
if (ORDINAL_WORD_DICTIONARY[num] !== undefined) {
|
|
289
292
|
return ORDINAL_WORD_DICTIONARY[num];
|
|
290
293
|
}
|
package/src/results.ts
CHANGED
|
@@ -16,7 +16,7 @@ export class ReferenceWithTimezone {
|
|
|
16
16
|
this.instant = input;
|
|
17
17
|
} else {
|
|
18
18
|
this.instant = input.instant ?? new Date();
|
|
19
|
-
this.timezoneOffset = toTimezoneOffset(input.timezone);
|
|
19
|
+
this.timezoneOffset = toTimezoneOffset(input.timezone, this.instant);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -138,8 +138,8 @@ export class ParsingComponents implements ParsedComponents {
|
|
|
138
138
|
return this.isCertain("weekday") && !this.isCertain("day") && !this.isCertain("month");
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
return this.isCertain("
|
|
141
|
+
isDateWithUnknownYear(): boolean {
|
|
142
|
+
return this.isCertain("month") && !this.isCertain("year");
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
isValidDate(): boolean {
|
package/src/timezone.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import dayjs from "dayjs";
|
|
2
|
+
import { TimezoneAbbrMap, Weekday, Month } from "./index";
|
|
3
|
+
|
|
4
|
+
export const TIMEZONE_ABBR_MAP: TimezoneAbbrMap = {
|
|
2
5
|
ACDT: 630,
|
|
3
6
|
ACST: 570,
|
|
4
7
|
ADT: -180,
|
|
@@ -32,7 +35,14 @@ export const TIMEZONE_ABBR_MAP = {
|
|
|
32
35
|
CCT: 390,
|
|
33
36
|
CDT: -300,
|
|
34
37
|
CEST: 120,
|
|
35
|
-
|
|
38
|
+
// Note: Many sources define CET as a constant UTC+1. In common usage, however,
|
|
39
|
+
// CET usually refers to the time observed in most of Europe, be it standard time or daylight saving time.
|
|
40
|
+
CET: {
|
|
41
|
+
timezoneOffsetDuringDst: 2 * 60,
|
|
42
|
+
timezoneOffsetNonDst: 60,
|
|
43
|
+
dstStart: (year: number) => getLastWeekdayOfMonth(year, Month.MARCH, Weekday.SUNDAY, 2),
|
|
44
|
+
dstEnd: (year: number) => getLastWeekdayOfMonth(year, Month.OCTOBER, Weekday.SUNDAY, 3),
|
|
45
|
+
},
|
|
36
46
|
CHADT: 825,
|
|
37
47
|
CHAST: 765,
|
|
38
48
|
CKT: -600,
|
|
@@ -40,6 +50,12 @@ export const TIMEZONE_ABBR_MAP = {
|
|
|
40
50
|
CLT: -240,
|
|
41
51
|
COT: -300,
|
|
42
52
|
CST: -360,
|
|
53
|
+
CT: {
|
|
54
|
+
timezoneOffsetDuringDst: -5 * 60,
|
|
55
|
+
timezoneOffsetNonDst: -6 * 60,
|
|
56
|
+
dstStart: (year: number) => getNthWeekdayOfMonth(year, Month.MARCH, Weekday.SUNDAY, 2, 2),
|
|
57
|
+
dstEnd: (year: number) => getNthWeekdayOfMonth(year, Month.NOVEMBER, Weekday.SUNDAY, 1, 2),
|
|
58
|
+
},
|
|
43
59
|
CVT: -60,
|
|
44
60
|
CXT: 420,
|
|
45
61
|
ChST: 600,
|
|
@@ -54,7 +70,12 @@ export const TIMEZONE_ABBR_MAP = {
|
|
|
54
70
|
EGST: 0,
|
|
55
71
|
EGT: -60,
|
|
56
72
|
EST: -300,
|
|
57
|
-
ET:
|
|
73
|
+
ET: {
|
|
74
|
+
timezoneOffsetDuringDst: -4 * 60,
|
|
75
|
+
timezoneOffsetNonDst: -5 * 60,
|
|
76
|
+
dstStart: (year: number) => getNthWeekdayOfMonth(year, Month.MARCH, Weekday.SUNDAY, 2, 2),
|
|
77
|
+
dstEnd: (year: number) => getNthWeekdayOfMonth(year, Month.NOVEMBER, Weekday.SUNDAY, 1, 2),
|
|
78
|
+
},
|
|
58
79
|
FJST: 780,
|
|
59
80
|
FJT: 720,
|
|
60
81
|
FKST: -180,
|
|
@@ -116,6 +137,12 @@ export const TIMEZONE_ABBR_MAP = {
|
|
|
116
137
|
MSD: 240,
|
|
117
138
|
MSK: 180,
|
|
118
139
|
MST: -420,
|
|
140
|
+
MT: {
|
|
141
|
+
timezoneOffsetDuringDst: -6 * 60,
|
|
142
|
+
timezoneOffsetNonDst: -7 * 60,
|
|
143
|
+
dstStart: (year: number) => getNthWeekdayOfMonth(year, Month.MARCH, Weekday.SUNDAY, 2, 2),
|
|
144
|
+
dstEnd: (year: number) => getNthWeekdayOfMonth(year, Month.NOVEMBER, Weekday.SUNDAY, 1, 2),
|
|
145
|
+
},
|
|
119
146
|
MUT: 240,
|
|
120
147
|
MVT: 300,
|
|
121
148
|
MYT: 480,
|
|
@@ -143,7 +170,12 @@ export const TIMEZONE_ABBR_MAP = {
|
|
|
143
170
|
PMST: -180,
|
|
144
171
|
PONT: 660,
|
|
145
172
|
PST: -480,
|
|
146
|
-
PT:
|
|
173
|
+
PT: {
|
|
174
|
+
timezoneOffsetDuringDst: -7 * 60,
|
|
175
|
+
timezoneOffsetNonDst: -8 * 60,
|
|
176
|
+
dstStart: (year: number) => getNthWeekdayOfMonth(year, Month.MARCH, Weekday.SUNDAY, 2, 2),
|
|
177
|
+
dstEnd: (year: number) => getNthWeekdayOfMonth(year, Month.NOVEMBER, Weekday.SUNDAY, 1, 2),
|
|
178
|
+
},
|
|
147
179
|
PWT: 540,
|
|
148
180
|
PYST: -180,
|
|
149
181
|
PYT: -240,
|
|
@@ -192,8 +224,67 @@ export const TIMEZONE_ABBR_MAP = {
|
|
|
192
224
|
YEKT: 360,
|
|
193
225
|
};
|
|
194
226
|
|
|
195
|
-
|
|
196
|
-
|
|
227
|
+
/**
|
|
228
|
+
* Get the date which is the nth occurence of a given weekday in a given month and year.
|
|
229
|
+
*
|
|
230
|
+
* @param year The year for which to find the date
|
|
231
|
+
* @param month The month in which the date occurs
|
|
232
|
+
* @param weekday The weekday on which the date occurs
|
|
233
|
+
* @param n The nth occurence of the given weekday on the month to return
|
|
234
|
+
* @param hour The hour of day which should be set on the returned date
|
|
235
|
+
* @return The date which is the nth occurence of a given weekday in a given
|
|
236
|
+
* month and year, at the given hour of day
|
|
237
|
+
*/
|
|
238
|
+
export function getNthWeekdayOfMonth(year: number, month: Month, weekday: Weekday, n: 1 | 2 | 3 | 4, hour = 0): Date {
|
|
239
|
+
let dayOfMonth = 0;
|
|
240
|
+
let i = 0;
|
|
241
|
+
while (i < n) {
|
|
242
|
+
dayOfMonth++;
|
|
243
|
+
const date = new Date(year, month - 1, dayOfMonth);
|
|
244
|
+
if (date.getDay() === weekday) i++;
|
|
245
|
+
}
|
|
246
|
+
return new Date(year, month - 1, dayOfMonth, hour);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Get the date which is the last occurence of a given weekday in a given month and year.
|
|
251
|
+
*
|
|
252
|
+
* @param year The year for which to find the date
|
|
253
|
+
* @param month The month in which the date occurs
|
|
254
|
+
* @param weekday The weekday on which the date occurs
|
|
255
|
+
* @param hour The hour of day which should be set on the returned date
|
|
256
|
+
* @return The date which is the last occurence of a given weekday in a given
|
|
257
|
+
* month and year, at the given hour of day
|
|
258
|
+
*/
|
|
259
|
+
export function getLastWeekdayOfMonth(year: number, month: Month, weekday: Weekday, hour = 0): Date {
|
|
260
|
+
// Procedure: Find the first weekday of the next month, compare with the given weekday,
|
|
261
|
+
// and use the difference to determine how many days to subtract from the first of the next month.
|
|
262
|
+
const oneIndexedWeekday = weekday === 0 ? 7 : weekday;
|
|
263
|
+
const date = new Date(year, month - 1 + 1, 1, 12);
|
|
264
|
+
const firstWeekdayNextMonth = date.getDay() === 0 ? 7 : date.getDay();
|
|
265
|
+
let dayDiff;
|
|
266
|
+
if (firstWeekdayNextMonth === oneIndexedWeekday) dayDiff = 7;
|
|
267
|
+
else if (firstWeekdayNextMonth < oneIndexedWeekday) dayDiff = 7 + firstWeekdayNextMonth - oneIndexedWeekday;
|
|
268
|
+
else dayDiff = firstWeekdayNextMonth - oneIndexedWeekday;
|
|
269
|
+
date.setDate(date.getDate() - dayDiff);
|
|
270
|
+
return new Date(year, month - 1, date.getDate(), hour);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Finds and returns timezone offset. If timezoneInput is numeric, it is returned. Otherwise, look for timezone offsets
|
|
275
|
+
* in the following order: timezoneOverrides -> {@link TIMEZONE_ABBR_MAP}.
|
|
276
|
+
*
|
|
277
|
+
* @param timezoneInput Uppercase timezone abbreviation or numeric offset in minutes
|
|
278
|
+
* @param date The date to use to determine whether to return DST offsets for ambiguous timezones
|
|
279
|
+
* @param timezoneOverrides Overrides for timezones
|
|
280
|
+
* @return timezone offset in minutes
|
|
281
|
+
*/
|
|
282
|
+
export function toTimezoneOffset(
|
|
283
|
+
timezoneInput?: string | number,
|
|
284
|
+
date?: Date,
|
|
285
|
+
timezoneOverrides: TimezoneAbbrMap = {}
|
|
286
|
+
): number | null {
|
|
287
|
+
if (timezoneInput == null) {
|
|
197
288
|
return null;
|
|
198
289
|
}
|
|
199
290
|
|
|
@@ -201,5 +292,31 @@ export function toTimezoneOffset(timezoneInput?: string | number): number | null
|
|
|
201
292
|
return timezoneInput;
|
|
202
293
|
}
|
|
203
294
|
|
|
204
|
-
|
|
295
|
+
const matchedTimezone = timezoneOverrides[timezoneInput] ?? TIMEZONE_ABBR_MAP[timezoneInput];
|
|
296
|
+
if (matchedTimezone == null) {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
// This means that we have matched an unambiguous timezone
|
|
300
|
+
if (typeof matchedTimezone == "number") {
|
|
301
|
+
return matchedTimezone;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// The matched timezone is an ambiguous timezone, where the offset depends on whether the context (refDate)
|
|
305
|
+
// is during daylight savings or not.
|
|
306
|
+
|
|
307
|
+
// Without refDate as context, there's no way to know if DST or non-DST offset should be used. Return null instead.
|
|
308
|
+
if (date == null) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Return DST offset if the refDate is during daylight savings
|
|
313
|
+
if (
|
|
314
|
+
dayjs(date).isAfter(matchedTimezone.dstStart(date.getFullYear())) &&
|
|
315
|
+
!dayjs(date).isAfter(matchedTimezone.dstEnd(date.getFullYear()))
|
|
316
|
+
) {
|
|
317
|
+
return matchedTimezone.timezoneOffsetDuringDst;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// refDate is not during DST => return non-DST offset
|
|
321
|
+
return matchedTimezone.timezoneOffsetNonDst;
|
|
205
322
|
}
|
|
@@ -180,22 +180,22 @@ test("Test - Range Expression", function () {
|
|
|
180
180
|
});
|
|
181
181
|
|
|
182
182
|
test("Test - Timezone extraction", function () {
|
|
183
|
-
testSingleCase(chrono.de, "um 14 Uhr", new Date(2016,
|
|
183
|
+
testSingleCase(chrono.de, "um 14 Uhr", new Date(2016, 1, 28), (result, text) => {
|
|
184
184
|
expect(result.text).toBe(text);
|
|
185
185
|
expect(result.start.isCertain("timezoneOffset")).toBe(false);
|
|
186
186
|
expect(!result.start.get("timezoneOffset")).not.toBeNull();
|
|
187
187
|
});
|
|
188
188
|
|
|
189
|
-
testSingleCase(chrono.de, "um 14 Uhr CET", new Date(2016,
|
|
189
|
+
testSingleCase(chrono.de, "um 14 Uhr CET", new Date(2016, 1, 28), (result, text) => {
|
|
190
190
|
expect(result.text).toBe(text);
|
|
191
191
|
expect(result.start.isCertain("timezoneOffset")).toBe(true);
|
|
192
192
|
expect(result.start.get("timezoneOffset")).toBe(60);
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
-
testSingleCase(chrono.de, "14 Uhr cet", new Date(2016,
|
|
195
|
+
testSingleCase(chrono.de, "14 Uhr cet", new Date(2016, 4, 28), (result, text) => {
|
|
196
196
|
expect(result.text).toBe(text);
|
|
197
197
|
expect(result.start.isCertain("timezoneOffset")).toBe(true);
|
|
198
|
-
expect(result.start.get("timezoneOffset")).toBe(
|
|
198
|
+
expect(result.start.get("timezoneOffset")).toBe(120);
|
|
199
199
|
});
|
|
200
200
|
});
|
|
201
201
|
|
|
@@ -209,15 +209,15 @@ test("Test - Random date + time expression", function () {
|
|
|
209
209
|
expect(result.start.get("hour")).toBe(12);
|
|
210
210
|
});
|
|
211
211
|
|
|
212
|
-
testSingleCase(chrono.de, "am Freitag um 14 Uhr cetteln wir etwas an", new Date(2016,
|
|
212
|
+
testSingleCase(chrono.de, "am Freitag um 14 Uhr cetteln wir etwas an", new Date(2016, 1, 28), (result, text) => {
|
|
213
213
|
expect(result.text).toBe("am Freitag um 14 Uhr");
|
|
214
214
|
expect(result.start.isCertain("timezoneOffset")).toBe(false);
|
|
215
215
|
expect(!result.start.get("timezoneOffset")).not.toBeNull();
|
|
216
216
|
});
|
|
217
217
|
|
|
218
|
-
testSingleCase(chrono.de, "Freitag um 14 Uhr CET", new Date(2016,
|
|
218
|
+
testSingleCase(chrono.de, "Freitag um 14 Uhr CET", new Date(2016, 4, 28), (result, text) => {
|
|
219
219
|
expect(result.text).toBe(text);
|
|
220
220
|
expect(result.start.isCertain("timezoneOffset")).toBe(true);
|
|
221
|
-
expect(result.start.get("timezoneOffset")).toBe(
|
|
221
|
+
expect(result.start.get("timezoneOffset")).toBe(120);
|
|
222
222
|
});
|
|
223
223
|
});
|
package/test/en/en_month.test.ts
CHANGED
|
@@ -117,6 +117,76 @@ test("Test - Month-Only expression", function () {
|
|
|
117
117
|
});
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
+
test("Test - Month-Only Range expression", () => {
|
|
121
|
+
testSingleCase(chrono, "From May to December", new Date(2023, 4 - 1, 9), (result) => {
|
|
122
|
+
expect(result.start.get("year")).toBe(2023);
|
|
123
|
+
expect(result.start.get("month")).toBe(5);
|
|
124
|
+
expect(result.end.get("year")).toBe(2023);
|
|
125
|
+
expect(result.end.get("month")).toBe(12);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
testSingleCase(chrono, "From December to May", new Date(2023, 4 - 1, 9), (result) => {
|
|
129
|
+
expect(result.start.get("year")).toBe(2022);
|
|
130
|
+
expect(result.start.get("month")).toBe(12);
|
|
131
|
+
expect(result.end.get("year")).toBe(2023);
|
|
132
|
+
expect(result.end.get("month")).toBe(5);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
testSingleCase(chrono, "From May to December, 2022", new Date(2023, 4 - 1, 9), (result) => {
|
|
136
|
+
expect(result.start.get("year")).toBe(2022);
|
|
137
|
+
expect(result.start.get("month")).toBe(5);
|
|
138
|
+
expect(result.end.get("year")).toBe(2022);
|
|
139
|
+
expect(result.end.get("month")).toBe(12);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
testSingleCase(chrono, "From December to May 2022", new Date(2023, 4 - 1, 9), (result) => {
|
|
143
|
+
expect(result.start.get("year")).toBe(2021);
|
|
144
|
+
expect(result.start.get("month")).toBe(12);
|
|
145
|
+
expect(result.end.get("year")).toBe(2022);
|
|
146
|
+
expect(result.end.get("month")).toBe(5);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
testSingleCase(chrono, "From December to May 2020", new Date(2023, 4 - 1, 9), (result) => {
|
|
150
|
+
expect(result.start.get("year")).toBe(2019);
|
|
151
|
+
expect(result.start.get("month")).toBe(12);
|
|
152
|
+
expect(result.end.get("year")).toBe(2020);
|
|
153
|
+
expect(result.end.get("month")).toBe(5);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
testSingleCase(chrono, "From December to May 2025", new Date(2023, 4 - 1, 9), (result) => {
|
|
157
|
+
expect(result.start.get("year")).toBe(2024);
|
|
158
|
+
expect(result.start.get("month")).toBe(12);
|
|
159
|
+
expect(result.end.get("year")).toBe(2025);
|
|
160
|
+
expect(result.end.get("month")).toBe(5);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("Test - Month with farward date option", () => {
|
|
165
|
+
testSingleCase(chrono, "in December", new Date(2023, 4 - 1, 9), { forwardDate: true }, (result) => {
|
|
166
|
+
expect(result.start.get("year")).toBe(2023);
|
|
167
|
+
expect(result.start.get("month")).toBe(12);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
testSingleCase(chrono, "in May", new Date(2023, 4 - 1, 9), { forwardDate: true }, (result) => {
|
|
171
|
+
expect(result.start.get("year")).toBe(2023);
|
|
172
|
+
expect(result.start.get("month")).toBe(5);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
testSingleCase(chrono, "From May to December", new Date(2023, 4 - 1, 9), { forwardDate: true }, (result) => {
|
|
176
|
+
expect(result.start.get("year")).toBe(2023);
|
|
177
|
+
expect(result.start.get("month")).toBe(5);
|
|
178
|
+
expect(result.end.get("year")).toBe(2023);
|
|
179
|
+
expect(result.end.get("month")).toBe(12);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
testSingleCase(chrono, "From December to May", new Date(2023, 4 - 1, 9), { forwardDate: true }, (result) => {
|
|
183
|
+
expect(result.start.get("year")).toBe(2023);
|
|
184
|
+
expect(result.start.get("month")).toBe(12);
|
|
185
|
+
expect(result.end.get("year")).toBe(2024);
|
|
186
|
+
expect(result.end.get("month")).toBe(5);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
120
190
|
test("Test - Month expression in context", function () {
|
|
121
191
|
testSingleCase(chrono, "The date is Sep 2012 is the date", (result) => {
|
|
122
192
|
expect(result.index).toBe(12);
|
|
@@ -300,6 +300,18 @@ test("Test - Before with reference", () => {
|
|
|
300
300
|
});
|
|
301
301
|
});
|
|
302
302
|
|
|
303
|
+
test("Test - Strict mode", function () {
|
|
304
|
+
testSingleCase(chrono.strict, "5 minutes ago", new Date(2012, 7, 10, 12, 14), (result, text) => {
|
|
305
|
+
expect(result.start.get("hour")).toBe(12);
|
|
306
|
+
expect(result.start.get("minute")).toBe(9);
|
|
307
|
+
expect(result.start).toBeDate(new Date(2012, 7, 10, 12, 9));
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
testUnexpectedResult(chrono.strict, "5m ago", new Date(2012, 7, 10, 12, 14));
|
|
311
|
+
testUnexpectedResult(chrono.strict, "5hr before", new Date(2012, 7, 10, 12, 14));
|
|
312
|
+
testUnexpectedResult(chrono.strict, "5 h ago", new Date(2012, 7, 10, 12, 14));
|
|
313
|
+
});
|
|
314
|
+
|
|
303
315
|
test("Test - Negative cases", function () {
|
|
304
316
|
testUnexpectedResult(chrono, "15 hours 29 min");
|
|
305
317
|
testUnexpectedResult(chrono, "a few hour");
|