chrono-node 2.3.5 → 2.3.8
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 +1 -1
- package/dist/common/refiners/ExtractTimezoneAbbrRefiner.js +6 -1
- package/dist/locales/de/constants.d.ts +3 -3
- package/dist/locales/de/constants.js +38 -20
- package/dist/locales/de/index.js +4 -0
- package/dist/locales/de/parsers/DESpecificTimeExpressionParser.d.ts +7 -0
- package/dist/locales/de/parsers/DESpecificTimeExpressionParser.js +114 -0
- package/dist/locales/de/parsers/DETimeExpressionParser.d.ts +0 -1
- package/dist/locales/de/parsers/DETimeExpressionParser.js +3 -21
- package/dist/locales/de/parsers/DETimeUnitRelativeFormatParser.d.ts +8 -0
- package/dist/locales/de/parsers/DETimeUnitRelativeFormatParser.js +34 -0
- package/dist/locales/en/constants.d.ts +2 -2
- package/dist/locales/en/constants.js +3 -0
- package/dist/locales/en/index.js +2 -1
- package/dist/locales/en/parsers/ENRelativeDateFormatParser.js +2 -2
- package/dist/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.js +1 -1
- package/dist/locales/en/refiners/ENMergeRelativeDateRefiner.d.ts +7 -0
- package/dist/locales/en/refiners/ENMergeRelativeDateRefiner.js +35 -0
- package/dist/locales/zh/hans/constants.d.ts +27 -0
- package/dist/locales/zh/hans/constants.js +51 -0
- package/dist/locales/zh/hans/index.d.ts +9 -0
- package/dist/locales/zh/hans/index.js +49 -0
- package/dist/locales/zh/hans/parsers/ZHHansCasualDateParser.d.ts +7 -0
- package/dist/locales/zh/hans/parsers/ZHHansCasualDateParser.js +138 -0
- package/dist/locales/zh/hans/parsers/ZHHansDateParser.d.ts +6 -0
- package/dist/locales/zh/hans/parsers/ZHHansDateParser.js +72 -0
- package/dist/locales/zh/hans/parsers/ZHHansDeadlineFormatParser.d.ts +6 -0
- package/dist/locales/zh/hans/parsers/ZHHansDeadlineFormatParser.js +78 -0
- package/dist/locales/zh/hans/parsers/ZHHansRelationWeekdayParser.d.ts +7 -0
- package/dist/locales/zh/hans/parsers/ZHHansRelationWeekdayParser.js +70 -0
- package/dist/locales/zh/hans/parsers/ZHHansTimeExpressionParser.d.ts +6 -0
- package/dist/locales/zh/hans/parsers/ZHHansTimeExpressionParser.js +438 -0
- package/dist/locales/zh/hans/parsers/ZHHansWeekdayParser.d.ts +7 -0
- package/dist/locales/zh/hans/parsers/ZHHansWeekdayParser.js +46 -0
- package/dist/locales/zh/hans/refiners/ZHHansMergeDateRangeRefiner.d.ts +4 -0
- package/dist/locales/zh/hans/refiners/ZHHansMergeDateRangeRefiner.js +12 -0
- package/dist/locales/zh/hans/refiners/ZHHansMergeDateTimeRefiner.d.ts +4 -0
- package/dist/locales/zh/hans/refiners/ZHHansMergeDateTimeRefiner.js +12 -0
- package/dist/locales/zh/hant/index.d.ts +9 -0
- package/dist/locales/zh/hant/index.js +49 -0
- package/dist/locales/zh/index.d.ts +2 -9
- package/dist/locales/zh/index.js +13 -46
- package/dist/results.d.ts +1 -1
- package/dist/results.js +1 -2
- package/dist/timezone.d.ts +1 -1
- package/dist/timezone.js +3 -3
- package/package.json +1 -1
- package/src/common/refiners/ExtractTimezoneAbbrRefiner.ts +11 -1
- package/src/locales/de/constants.ts +42 -22
- package/src/locales/de/index.ts +4 -0
- package/src/locales/de/parsers/DESpecificTimeExpressionParser.ts +150 -0
- package/src/locales/de/parsers/DETimeExpressionParser.ts +4 -23
- package/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts +42 -0
- package/src/locales/en/constants.ts +5 -2
- package/src/locales/en/index.ts +2 -1
- package/src/locales/en/parsers/ENMonthNameLittleEndianParser.ts +0 -2
- package/src/locales/en/parsers/ENRelativeDateFormatParser.ts +2 -2
- package/src/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.ts +1 -1
- package/src/locales/en/refiners/ENMergeRelativeDateRefiner.ts +58 -0
- package/src/locales/zh/hans/constants.ts +52 -0
- package/src/locales/zh/hans/index.ts +62 -0
- package/src/locales/zh/hans/parsers/ZHHansCasualDateParser.ts +128 -0
- package/src/locales/zh/hans/parsers/ZHHansDateParser.ts +75 -0
- package/src/locales/zh/hans/parsers/ZHHansDeadlineFormatParser.ts +81 -0
- package/src/locales/zh/hans/parsers/ZHHansRelationWeekdayParser.ts +69 -0
- package/src/locales/zh/hans/parsers/ZHHansTimeExpressionParser.ts +424 -0
- package/src/locales/zh/hans/parsers/ZHHansWeekdayParser.ts +46 -0
- package/src/locales/zh/hans/refiners/ZHHansMergeDateRangeRefiner.ts +7 -0
- package/src/locales/zh/hans/refiners/ZHHansMergeDateTimeRefiner.ts +7 -0
- package/src/locales/zh/hant/index.ts +63 -0
- package/src/locales/zh/index.ts +2 -63
- package/src/results.ts +2 -3
- package/src/timezone.ts +4 -4
- package/test/de/de_month_name_little_endian.test.ts +12 -0
- package/test/de/de_time_exp.test.ts +59 -0
- package/test/de/de_time_units_casual_relative.test.ts +108 -0
- package/test/de/de_year.test.ts +147 -0
- package/test/en/en_merging_relative_dates.test.ts +51 -0
- package/test/en/en_month.test.ts +13 -0
- package/test/en/en_relative.test.ts +61 -2
- package/test/en/en_time_units_ago.test.ts +3 -3
- package/test/en/en_time_units_casual_relative.test.ts +16 -0
- package/test/en/en_time_units_within.test.ts +2 -2
- package/test/en/en_timezone_exp.test.ts +3 -3
- package/test/fr/fr_time_units_ago.test.ts +3 -3
- package/test/fr/fr_time_units_within.test.ts +2 -2
- package/test/nl/nl_relative.test.ts +2 -2
- package/test/nl/nl_time_units_ago.test.ts +3 -3
- package/test/system_timezone.test.ts +22 -0
- package/test/zh/zh_hans_casual.test.ts +228 -0
- package/test/zh/zh_hans_date.test.ts +102 -0
- package/test/zh/zh_hans_deadline.test.ts +136 -0
- package/test/zh/zh_hans_time_exp.test.ts +182 -0
- package/test/zh/zh_hans_weekday.test.ts +132 -0
- package/test/zh/zh_hant_date.test.ts +0 -1
package/dist/results.js
CHANGED
|
@@ -15,7 +15,6 @@ class ReferenceWithTimezone {
|
|
|
15
15
|
input = input !== null && input !== void 0 ? input : new Date();
|
|
16
16
|
if (input instanceof Date) {
|
|
17
17
|
this.instant = input;
|
|
18
|
-
this.timezoneOffset = -input.getTimezoneOffset();
|
|
19
18
|
}
|
|
20
19
|
else {
|
|
21
20
|
this.instant = (_a = input.instant) !== null && _a !== void 0 ? _a : new Date();
|
|
@@ -113,7 +112,7 @@ class ParsingComponents {
|
|
|
113
112
|
return true;
|
|
114
113
|
}
|
|
115
114
|
toString() {
|
|
116
|
-
return `[ParsingComponents {knownValues: ${JSON.stringify(this.knownValues)}, impliedValues: ${JSON.stringify(this.impliedValues)}}]`;
|
|
115
|
+
return `[ParsingComponents {knownValues: ${JSON.stringify(this.knownValues)}, impliedValues: ${JSON.stringify(this.impliedValues)}}, reference: ${JSON.stringify(this.reference)}]`;
|
|
117
116
|
}
|
|
118
117
|
dayjs() {
|
|
119
118
|
return dayjs_1.default(this.date());
|
package/dist/timezone.d.ts
CHANGED
|
@@ -191,4 +191,4 @@ export declare const TIMEZONE_ABBR_MAP: {
|
|
|
191
191
|
YEKST: number;
|
|
192
192
|
YEKT: number;
|
|
193
193
|
};
|
|
194
|
-
export declare function toTimezoneOffset(timezoneInput
|
|
194
|
+
export declare function toTimezoneOffset(timezoneInput?: string | number): number | null;
|
package/dist/timezone.js
CHANGED
|
@@ -117,7 +117,7 @@ exports.TIMEZONE_ABBR_MAP = {
|
|
|
117
117
|
MHT: 720,
|
|
118
118
|
MMT: 390,
|
|
119
119
|
MSD: 240,
|
|
120
|
-
MSK:
|
|
120
|
+
MSK: 180,
|
|
121
121
|
MST: -420,
|
|
122
122
|
MUT: 240,
|
|
123
123
|
MVT: 300,
|
|
@@ -196,12 +196,12 @@ exports.TIMEZONE_ABBR_MAP = {
|
|
|
196
196
|
};
|
|
197
197
|
function toTimezoneOffset(timezoneInput) {
|
|
198
198
|
var _a;
|
|
199
|
-
if (timezoneInput === null) {
|
|
199
|
+
if (timezoneInput === null || timezoneInput === undefined) {
|
|
200
200
|
return null;
|
|
201
201
|
}
|
|
202
202
|
if (typeof timezoneInput === "number") {
|
|
203
203
|
return timezoneInput;
|
|
204
204
|
}
|
|
205
|
-
return (_a = exports.TIMEZONE_ABBR_MAP[timezoneInput]) !== null && _a !== void 0 ? _a :
|
|
205
|
+
return (_a = exports.TIMEZONE_ABBR_MAP[timezoneInput]) !== null && _a !== void 0 ? _a : null;
|
|
206
206
|
}
|
|
207
207
|
exports.toTimezoneOffset = toTimezoneOffset;
|
package/package.json
CHANGED
|
@@ -221,7 +221,9 @@ export default class ExtractTimezoneAbbrRefiner implements Refiner {
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
context.debug(() => {
|
|
224
|
-
console.log(
|
|
224
|
+
console.log(
|
|
225
|
+
`Extracting timezone: '${timezoneAbbr}' into: ${extractedTimezoneOffset} for: ${result.start}`
|
|
226
|
+
);
|
|
225
227
|
});
|
|
226
228
|
|
|
227
229
|
const currentTimezoneOffset = result.start.get("timezoneOffset");
|
|
@@ -240,6 +242,14 @@ export default class ExtractTimezoneAbbrRefiner implements Refiner {
|
|
|
240
242
|
}
|
|
241
243
|
}
|
|
242
244
|
|
|
245
|
+
if (result.start.isOnlyDate()) {
|
|
246
|
+
// If the time is not explicitly mentioned,
|
|
247
|
+
// Then, we also want to double check the abbr case (e.g. "GET" not "get")
|
|
248
|
+
if (timezoneAbbr != match[1]) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
243
253
|
result.text += match[0];
|
|
244
254
|
|
|
245
255
|
if (!result.start.isCertain("timezoneOffset")) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OpUnitType } from "dayjs";
|
|
1
|
+
import { OpUnitType, QUnitType } from "dayjs";
|
|
2
2
|
import { matchAnyPattern, repeatedTimeunitPattern } from "../../utils/pattern";
|
|
3
3
|
import { findMostLikelyADYear } from "../../calculation/years";
|
|
4
4
|
import { TimeUnits } from "../../utils/timeunits";
|
|
@@ -22,9 +22,12 @@ export const WEEKDAY_DICTIONARY: { [word: string]: number } = {
|
|
|
22
22
|
|
|
23
23
|
export const MONTH_DICTIONARY: { [word: string]: number } = {
|
|
24
24
|
"januar": 1,
|
|
25
|
+
"jänner": 1,
|
|
26
|
+
"janner": 1,
|
|
25
27
|
"jan": 1,
|
|
26
28
|
"jan.": 1,
|
|
27
29
|
"februar": 2,
|
|
30
|
+
"feber": 2,
|
|
28
31
|
"feb": 2,
|
|
29
32
|
"feb.": 2,
|
|
30
33
|
"märz": 3,
|
|
@@ -64,6 +67,10 @@ export const MONTH_DICTIONARY: { [word: string]: number } = {
|
|
|
64
67
|
|
|
65
68
|
export const INTEGER_WORD_DICTIONARY: { [word: string]: number } = {
|
|
66
69
|
"eins": 1,
|
|
70
|
+
"eine": 1,
|
|
71
|
+
"einem": 1,
|
|
72
|
+
"einen": 1,
|
|
73
|
+
"einer": 1,
|
|
67
74
|
"zwei": 2,
|
|
68
75
|
"drei": 3,
|
|
69
76
|
"vier": 4,
|
|
@@ -79,29 +86,37 @@ export const INTEGER_WORD_DICTIONARY: { [word: string]: number } = {
|
|
|
79
86
|
"zwoelf": 12,
|
|
80
87
|
};
|
|
81
88
|
|
|
82
|
-
export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType } = {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
89
|
+
export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType | QUnitType } = {
|
|
90
|
+
sek: "second",
|
|
91
|
+
sekunde: "second",
|
|
92
|
+
sekunden: "second",
|
|
86
93
|
min: "minute",
|
|
87
|
-
mins: "minute",
|
|
88
94
|
minute: "minute",
|
|
89
|
-
|
|
95
|
+
minuten: "minute",
|
|
90
96
|
h: "hour",
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
97
|
+
std: "hour",
|
|
98
|
+
stunde: "hour",
|
|
99
|
+
stunden: "hour",
|
|
100
|
+
tag: "d",
|
|
101
|
+
tage: "d",
|
|
102
|
+
tagen: "d",
|
|
103
|
+
woche: "week",
|
|
104
|
+
wochen: "week",
|
|
105
|
+
monat: "month",
|
|
106
|
+
monate: "month",
|
|
107
|
+
monaten: "month",
|
|
108
|
+
monats: "month",
|
|
109
|
+
quartal: "quarter",
|
|
110
|
+
quartals: "quarter",
|
|
111
|
+
quartale: "quarter",
|
|
112
|
+
quartalen: "quarter",
|
|
113
|
+
a: "year",
|
|
114
|
+
j: "year",
|
|
115
|
+
jr: "year",
|
|
116
|
+
jahr: "year",
|
|
117
|
+
jahre: "year",
|
|
118
|
+
jahren: "year",
|
|
119
|
+
jahres: "year",
|
|
105
120
|
};
|
|
106
121
|
|
|
107
122
|
//-----------------------------
|
|
@@ -131,7 +146,7 @@ export function parseNumberPattern(match: string): number {
|
|
|
131
146
|
|
|
132
147
|
//-----------------------------
|
|
133
148
|
|
|
134
|
-
export const YEAR_PATTERN = `(?:[0-9]{1,4}(?:\\s*[vn]\\.?\\s*C(?:hr)
|
|
149
|
+
export const YEAR_PATTERN = `(?:[0-9]{1,4}(?:\\s*[vn]\\.?\\s*(?:C(?:hr)?|(?:u\\.?|d\\.?(?:\\s*g\\.?)?)?\\s*Z)\\.?|\\s*(?:u\\.?|d\\.?(?:\\s*g\\.)?)\\s*Z\\.?)?)`;
|
|
135
150
|
export function parseYear(match: string): number {
|
|
136
151
|
if (/v/i.test(match)) {
|
|
137
152
|
// v.Chr.
|
|
@@ -143,6 +158,11 @@ export function parseYear(match: string): number {
|
|
|
143
158
|
return parseInt(match.replace(/[^0-9]+/gi, ""));
|
|
144
159
|
}
|
|
145
160
|
|
|
161
|
+
if (/z/i.test(match)) {
|
|
162
|
+
// n.Chr. as "uZ" or "dgZ"
|
|
163
|
+
return parseInt(match.replace(/[^0-9]+/gi, ""));
|
|
164
|
+
}
|
|
165
|
+
|
|
146
166
|
const rawYearNumber = parseInt(match);
|
|
147
167
|
return findMostLikelyADYear(rawYearNumber);
|
|
148
168
|
}
|
package/src/locales/de/index.ts
CHANGED
|
@@ -5,11 +5,13 @@ import SlashDateFormatParser from "../../common/parsers/SlashDateFormatParser";
|
|
|
5
5
|
import ISOFormatParser from "../../common/parsers/ISOFormatParser";
|
|
6
6
|
import DETimeExpressionParser from "./parsers/DETimeExpressionParser";
|
|
7
7
|
import DEWeekdayParser from "./parsers/DEWeekdayParser";
|
|
8
|
+
import DESpecificTimeExpressionParser from "./parsers/DESpecificTimeExpressionParser";
|
|
8
9
|
import DEMergeDateRangeRefiner from "./refiners/DEMergeDateRangeRefiner";
|
|
9
10
|
import DEMergeDateTimeRefiner from "./refiners/DEMergeDateTimeRefiner";
|
|
10
11
|
import DECasualDateParser from "./parsers/DECasualDateParser";
|
|
11
12
|
import DECasualTimeParser from "./parsers/DECasualTimeParser";
|
|
12
13
|
import DEMonthNameLittleEndianParser from "./parsers/DEMonthNameLittleEndianParser";
|
|
14
|
+
import DETimeUnitRelativeFormatParser from "./parsers/DETimeUnitRelativeFormatParser";
|
|
13
15
|
|
|
14
16
|
// Shortcuts
|
|
15
17
|
export const casual = new Chrono(createCasualConfiguration());
|
|
@@ -27,6 +29,7 @@ export function createCasualConfiguration(littleEndian = true): Configuration {
|
|
|
27
29
|
const option = createConfiguration(false, littleEndian);
|
|
28
30
|
option.parsers.unshift(new DECasualTimeParser());
|
|
29
31
|
option.parsers.unshift(new DECasualDateParser());
|
|
32
|
+
option.parsers.unshift(new DETimeUnitRelativeFormatParser());
|
|
30
33
|
return option;
|
|
31
34
|
}
|
|
32
35
|
|
|
@@ -37,6 +40,7 @@ export function createConfiguration(strictMode = true, littleEndian = true): Con
|
|
|
37
40
|
new ISOFormatParser(),
|
|
38
41
|
new SlashDateFormatParser(littleEndian),
|
|
39
42
|
new DETimeExpressionParser(),
|
|
43
|
+
new DESpecificTimeExpressionParser(),
|
|
40
44
|
new DEMonthNameLittleEndianParser(),
|
|
41
45
|
new DEWeekdayParser(),
|
|
42
46
|
],
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { Parser, ParsingContext } from "../../../chrono";
|
|
2
|
+
import { ParsingComponents, ParsingResult } from "../../../results";
|
|
3
|
+
import { Meridiem } from "../../../index";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 8h10m00s
|
|
7
|
+
* 8h10m00
|
|
8
|
+
* 8h10
|
|
9
|
+
* 8 Uhr
|
|
10
|
+
* 8h10m00s Uhr
|
|
11
|
+
* 8:10 Uhr
|
|
12
|
+
*/
|
|
13
|
+
const FIRST_REG_PATTERN = new RegExp(
|
|
14
|
+
"(^|\\s|T)" +
|
|
15
|
+
"(?:(?:um|von)\\s*)?" +
|
|
16
|
+
"(\\d{1,2})(?:h|:)?" +
|
|
17
|
+
"(?:(\\d{1,2})(?:m|:)?)?" +
|
|
18
|
+
"(?:(\\d{1,2})(?:s)?)?" +
|
|
19
|
+
"(?:\\s*Uhr)?" +
|
|
20
|
+
"(?:\\s*(morgens|vormittags|nachmittags|abends|nachts|am\\s+(?:Morgen|Vormittag|Nachmittag|Abend)|in\\s+der\\s+Nacht))?" +
|
|
21
|
+
"(?=\\W|$)",
|
|
22
|
+
"i"
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const SECOND_REG_PATTERN = new RegExp(
|
|
26
|
+
"^\\s*(\\-|\\–|\\~|\\〜|bis(?:\\s+um)?|\\?)\\s*" +
|
|
27
|
+
"(\\d{1,2})(?:h|:)?" +
|
|
28
|
+
"(?:(\\d{1,2})(?:m|:)?)?" +
|
|
29
|
+
"(?:(\\d{1,2})(?:s)?)?" +
|
|
30
|
+
"(?:\\s*Uhr)?" +
|
|
31
|
+
"(?:\\s*(morgens|vormittags|nachmittags|abends|nachts|am\\s+(?:Morgen|Vormittag|Nachmittag|Abend)|in\\s+der\\s+Nacht))?" +
|
|
32
|
+
"(?=\\W|$)",
|
|
33
|
+
"i"
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const HOUR_GROUP = 2;
|
|
37
|
+
const MINUTE_GROUP = 3;
|
|
38
|
+
const SECOND_GROUP = 4;
|
|
39
|
+
const AM_PM_HOUR_GROUP = 5;
|
|
40
|
+
|
|
41
|
+
export default class DESpecificTimeExpressionParser implements Parser {
|
|
42
|
+
pattern(context): RegExp {
|
|
43
|
+
return FIRST_REG_PATTERN;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
extract(context: ParsingContext, match: RegExpMatchArray): ParsingResult | null {
|
|
47
|
+
const result = context.createParsingResult(match.index + match[1].length, match[0].substring(match[1].length));
|
|
48
|
+
|
|
49
|
+
// This looks more like a year e.g. 2020
|
|
50
|
+
if (result.text.match(/^\d{4}$/)) {
|
|
51
|
+
match.index += match[0].length;
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
result.start = DESpecificTimeExpressionParser.extractTimeComponent(result.start.clone(), match);
|
|
56
|
+
if (!result.start) {
|
|
57
|
+
match.index += match[0].length;
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const remainingText = context.text.substring(match.index + match[0].length);
|
|
62
|
+
const secondMatch = SECOND_REG_PATTERN.exec(remainingText);
|
|
63
|
+
if (secondMatch) {
|
|
64
|
+
result.end = DESpecificTimeExpressionParser.extractTimeComponent(result.start.clone(), secondMatch);
|
|
65
|
+
if (result.end) {
|
|
66
|
+
result.text += secondMatch[0];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private static extractTimeComponent(
|
|
74
|
+
extractingComponents: ParsingComponents,
|
|
75
|
+
match: RegExpMatchArray
|
|
76
|
+
): ParsingComponents | null {
|
|
77
|
+
let hour = 0;
|
|
78
|
+
let minute = 0;
|
|
79
|
+
let meridiem = null;
|
|
80
|
+
|
|
81
|
+
// ----- Hours
|
|
82
|
+
hour = parseInt(match[HOUR_GROUP]);
|
|
83
|
+
|
|
84
|
+
// ----- Minutes
|
|
85
|
+
if (match[MINUTE_GROUP] != null) {
|
|
86
|
+
minute = parseInt(match[MINUTE_GROUP]);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (minute >= 60 || hour > 24) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (hour >= 12) {
|
|
94
|
+
meridiem = Meridiem.PM;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ----- AM & PM
|
|
98
|
+
if (match[AM_PM_HOUR_GROUP] != null) {
|
|
99
|
+
if (hour > 12) return null;
|
|
100
|
+
const ampm = match[AM_PM_HOUR_GROUP].toLowerCase();
|
|
101
|
+
if (ampm.match(/morgen|vormittag/)) {
|
|
102
|
+
meridiem = Meridiem.AM;
|
|
103
|
+
if (hour == 12) {
|
|
104
|
+
hour = 0;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (ampm.match(/nachmittag|abend/)) {
|
|
109
|
+
meridiem = Meridiem.PM;
|
|
110
|
+
if (hour != 12) {
|
|
111
|
+
hour += 12;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (ampm.match(/nacht/)) {
|
|
116
|
+
if (hour == 12) {
|
|
117
|
+
meridiem = Meridiem.AM;
|
|
118
|
+
hour = 0;
|
|
119
|
+
} else if (hour < 6) {
|
|
120
|
+
meridiem = Meridiem.AM;
|
|
121
|
+
} else {
|
|
122
|
+
meridiem = Meridiem.PM;
|
|
123
|
+
hour += 12;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
extractingComponents.assign("hour", hour);
|
|
129
|
+
extractingComponents.assign("minute", minute);
|
|
130
|
+
if (meridiem !== null) {
|
|
131
|
+
extractingComponents.assign("meridiem", meridiem);
|
|
132
|
+
} else {
|
|
133
|
+
if (hour < 12) {
|
|
134
|
+
extractingComponents.imply("meridiem", Meridiem.AM);
|
|
135
|
+
} else {
|
|
136
|
+
extractingComponents.imply("meridiem", Meridiem.PM);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ----- Second
|
|
141
|
+
if (match[SECOND_GROUP] != null) {
|
|
142
|
+
const second = parseInt(match[SECOND_GROUP]);
|
|
143
|
+
if (second >= 60) return null;
|
|
144
|
+
|
|
145
|
+
extractingComponents.assign("second", second);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return extractingComponents;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { AbstractTimeExpressionParser } from "../../../common/parsers/AbstractTimeExpressionParser";
|
|
2
2
|
import { ParsingComponents } from "../../../results";
|
|
3
3
|
import { ParsingContext } from "../../../chrono";
|
|
4
|
-
import { Meridiem } from "../../../index";
|
|
5
4
|
|
|
6
5
|
export default class DETimeExpressionParser extends AbstractTimeExpressionParser {
|
|
7
6
|
primaryPrefix(): string {
|
|
@@ -12,30 +11,12 @@ export default class DETimeExpressionParser extends AbstractTimeExpressionParser
|
|
|
12
11
|
return "\\s*(?:\\-|\\–|\\~|\\〜|bis)\\s*";
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
primarySuffix(): string {
|
|
16
|
-
return "(?:\\s*uhr)?(?:\\s*(?:morgens|vormittags|nachmittags|abends|nachts))?(?=\\W|$)";
|
|
17
|
-
}
|
|
18
|
-
|
|
19
14
|
extractPrimaryTimeComponents(context: ParsingContext, match: RegExpMatchArray): ParsingComponents | null {
|
|
20
|
-
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
components.assign("meridiem", Meridiem.AM);
|
|
24
|
-
const hour = components.get("hour");
|
|
25
|
-
if (hour < 12) {
|
|
26
|
-
components.assign("hour", components.get("hour"));
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (match[0].endsWith("nachmittags") || match[0].endsWith("abends") || match[0].endsWith("nachts")) {
|
|
31
|
-
components.assign("meridiem", Meridiem.PM);
|
|
32
|
-
const hour = components.get("hour");
|
|
33
|
-
if (hour < 12) {
|
|
34
|
-
components.assign("hour", components.get("hour") + 12);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
15
|
+
// This looks more like a year e.g. 2020
|
|
16
|
+
if (match[0].match(/^\s*\d{4}\s*$/)) {
|
|
17
|
+
return null;
|
|
37
18
|
}
|
|
38
19
|
|
|
39
|
-
return
|
|
20
|
+
return super.extractPrimaryTimeComponents(context, match);
|
|
40
21
|
}
|
|
41
22
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ParsingContext } from "../../../chrono";
|
|
2
|
+
import { NUMBER_PATTERN, parseNumberPattern, TIME_UNIT_DICTIONARY } from "../constants";
|
|
3
|
+
import { ParsingComponents } from "../../../results";
|
|
4
|
+
import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary";
|
|
5
|
+
import { reverseTimeUnits } from "../../../utils/timeunits";
|
|
6
|
+
import { matchAnyPattern } from "../../../utils/pattern";
|
|
7
|
+
|
|
8
|
+
export default class DETimeUnitAgoFormatParser extends AbstractParserWithWordBoundaryChecking {
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
innerPattern(): RegExp {
|
|
14
|
+
return new RegExp(
|
|
15
|
+
`(?:\\s*((?:nächste|kommende|folgende|letzte|vergangene|vorige|vor(?:her|an)gegangene)(?:s|n|m|r)?|vor|in)\\s*)?` +
|
|
16
|
+
`(${NUMBER_PATTERN})?` +
|
|
17
|
+
`(?:\\s*(nächste|kommende|folgende|letzte|vergangene|vorige|vor(?:her|an)gegangene)(?:s|n|m|r)?)?` +
|
|
18
|
+
`\\s*(${matchAnyPattern(TIME_UNIT_DICTIONARY)})`,
|
|
19
|
+
"i"
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
innerExtract(context: ParsingContext, match: RegExpMatchArray) {
|
|
24
|
+
const num = match[2] ? parseNumberPattern(match[2]) : 1;
|
|
25
|
+
const unit = TIME_UNIT_DICTIONARY[match[4].toLowerCase()];
|
|
26
|
+
let timeUnits = {};
|
|
27
|
+
timeUnits[unit] = num;
|
|
28
|
+
|
|
29
|
+
// Modifier
|
|
30
|
+
let modifier = match[1] || match[3] || "";
|
|
31
|
+
modifier = modifier.toLowerCase();
|
|
32
|
+
if (!modifier) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (/vor/.test(modifier) || /letzte/.test(modifier) || /vergangen/.test(modifier)) {
|
|
37
|
+
timeUnits = reverseTimeUnits(timeUnits);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return ParsingComponents.createRelativeFromReference(context.reference, timeUnits);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OpUnitType } from "dayjs";
|
|
1
|
+
import { OpUnitType, QUnitType } from "dayjs";
|
|
2
2
|
import { matchAnyPattern, repeatedTimeunitPattern } from "../../utils/pattern";
|
|
3
3
|
import { findMostLikelyADYear } from "../../calculation/years";
|
|
4
4
|
import { TimeUnits } from "../../utils/timeunits";
|
|
@@ -133,7 +133,7 @@ export const ORDINAL_WORD_DICTIONARY: { [word: string]: number } = {
|
|
|
133
133
|
"thirty-first": 31,
|
|
134
134
|
};
|
|
135
135
|
|
|
136
|
-
export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType } = {
|
|
136
|
+
export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType | QUnitType } = {
|
|
137
137
|
sec: "second",
|
|
138
138
|
second: "second",
|
|
139
139
|
seconds: "second",
|
|
@@ -152,6 +152,9 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType } = {
|
|
|
152
152
|
weeks: "week",
|
|
153
153
|
month: "month",
|
|
154
154
|
months: "month",
|
|
155
|
+
qtr: "quarter",
|
|
156
|
+
quarter: "quarter",
|
|
157
|
+
quarters: "quarter",
|
|
155
158
|
y: "year",
|
|
156
159
|
yr: "year",
|
|
157
160
|
year: "year",
|
package/src/locales/en/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ import { ParsedResult, ParsingOption } from "../../index";
|
|
|
26
26
|
import { Chrono, Configuration } from "../../chrono";
|
|
27
27
|
import SlashDateFormatParser from "../../common/parsers/SlashDateFormatParser";
|
|
28
28
|
import ENTimeUnitCasualRelativeFormatParser from "./parsers/ENTimeUnitCasualRelativeFormatParser";
|
|
29
|
+
import ENMergeRelativeDateRefiner from "./refiners/ENMergeRelativeDateRefiner";
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* Chrono object configured for parsing *casual* English
|
|
@@ -91,7 +92,7 @@ export function createConfiguration(strictMode = true, littleEndian = false): Co
|
|
|
91
92
|
new ENTimeUnitAgoFormatParser(strictMode),
|
|
92
93
|
new ENTimeUnitLaterFormatParser(strictMode),
|
|
93
94
|
],
|
|
94
|
-
refiners: [new ENMergeDateTimeRefiner(), new ENMergeDateRangeRefiner()],
|
|
95
|
+
refiners: [new ENMergeRelativeDateRefiner(), new ENMergeDateTimeRefiner(), new ENMergeDateRangeRefiner()],
|
|
95
96
|
},
|
|
96
97
|
strictMode
|
|
97
98
|
);
|
|
@@ -36,8 +36,6 @@ export default class ENMonthNameLittleEndianParser extends AbstractParserWithWor
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
innerExtract(context: ParsingContext, match: RegExpMatchArray): ParsingResult {
|
|
39
|
-
//console.log(match)
|
|
40
|
-
|
|
41
39
|
const result = context.createParsingResult(match.index, match[0]);
|
|
42
40
|
|
|
43
41
|
const month = MONTH_DICTIONARY[match[MONTH_NAME_GROUP].toLowerCase()];
|
|
@@ -6,7 +6,7 @@ import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/
|
|
|
6
6
|
import { matchAnyPattern } from "../../../utils/pattern";
|
|
7
7
|
|
|
8
8
|
const PATTERN = new RegExp(
|
|
9
|
-
`(this|
|
|
9
|
+
`(this|last|past|next|after\\s*this)\\s*(${matchAnyPattern(TIME_UNIT_DICTIONARY)})(?=\\s*)` + "(?=\\W|$)",
|
|
10
10
|
"i"
|
|
11
11
|
);
|
|
12
12
|
|
|
@@ -23,7 +23,7 @@ export default class ENRelativeDateFormatParser extends AbstractParserWithWordBo
|
|
|
23
23
|
const unitWord = match[RELATIVE_WORD_GROUP].toLowerCase();
|
|
24
24
|
const timeunit = TIME_UNIT_DICTIONARY[unitWord];
|
|
25
25
|
|
|
26
|
-
if (modifier == "next") {
|
|
26
|
+
if (modifier == "next" || modifier.startsWith("after")) {
|
|
27
27
|
const timeUnits = {};
|
|
28
28
|
timeUnits[timeunit] = 1;
|
|
29
29
|
return ParsingComponents.createRelativeFromReference(context.reference, timeUnits);
|
|
@@ -4,7 +4,7 @@ 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(`(this|last|past|next|\\+|-)\\s*(${TIME_UNITS_PATTERN})(?=\\W|$)`, "i");
|
|
7
|
+
const PATTERN = new RegExp(`(this|last|past|next|after|\\+|-)\\s*(${TIME_UNITS_PATTERN})(?=\\W|$)`, "i");
|
|
8
8
|
|
|
9
9
|
export default class ENTimeUnitCasualRelativeFormatParser extends AbstractParserWithWordBoundaryChecking {
|
|
10
10
|
innerPattern(): RegExp {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { MergingRefiner } from "../../../common/abstractRefiners";
|
|
2
|
+
import { ParsingComponents, ParsingResult, ReferenceWithTimezone } from "../../../results";
|
|
3
|
+
import { parseTimeUnits } from "../constants";
|
|
4
|
+
import { reverseTimeUnits } from "../../../utils/timeunits";
|
|
5
|
+
|
|
6
|
+
function hasImpliedEarlierReferenceDate(result: ParsingResult): boolean {
|
|
7
|
+
return result.text.match(/\s+(before|from)$/i) != null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function hasImpliedLaterReferenceDate(result: ParsingResult): boolean {
|
|
11
|
+
return result.text.match(/\s+(after|since)$/i) != null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Merges an absolute date with a relative date.
|
|
16
|
+
* - 2 weeks before 2020-02-13
|
|
17
|
+
* - 2 days after next Friday
|
|
18
|
+
*/
|
|
19
|
+
export default class ENMergeRelativeDateRefiner extends MergingRefiner {
|
|
20
|
+
patternBetween(): RegExp {
|
|
21
|
+
return /^\s*$/i;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
shouldMergeResults(textBetween: string, currentResult: ParsingResult, nextResult: ParsingResult): boolean {
|
|
25
|
+
// Dates need to be next to each other to get merged
|
|
26
|
+
if (!textBetween.match(this.patternBetween())) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Check if any relative tokens were swallowed by the first date.
|
|
31
|
+
// E.g. [<relative_date1> from] [<date2>]
|
|
32
|
+
if (!hasImpliedEarlierReferenceDate(currentResult) && !hasImpliedLaterReferenceDate(currentResult)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// make sure that <date2> implies an absolute date
|
|
37
|
+
return !!nextResult.start.get("day") && !!nextResult.start.get("month") && !!nextResult.start.get("year");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
mergeResults(textBetween: string, currentResult: ParsingResult, nextResult: ParsingResult): ParsingResult {
|
|
41
|
+
let timeUnits = parseTimeUnits(currentResult.text);
|
|
42
|
+
if (hasImpliedEarlierReferenceDate(currentResult)) {
|
|
43
|
+
timeUnits = reverseTimeUnits(timeUnits);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const components = ParsingComponents.createRelativeFromReference(
|
|
47
|
+
new ReferenceWithTimezone(nextResult.start.date()),
|
|
48
|
+
timeUnits
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
return new ParsingResult(
|
|
52
|
+
nextResult.reference,
|
|
53
|
+
currentResult.index,
|
|
54
|
+
`${currentResult.text}${textBetween}${nextResult.text}`,
|
|
55
|
+
components
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export const NUMBER = {
|
|
2
|
+
"零": 0,
|
|
3
|
+
"〇": 0,
|
|
4
|
+
"一": 1,
|
|
5
|
+
"二": 2,
|
|
6
|
+
"两": 2,
|
|
7
|
+
"三": 3,
|
|
8
|
+
"四": 4,
|
|
9
|
+
"五": 5,
|
|
10
|
+
"六": 6,
|
|
11
|
+
"七": 7,
|
|
12
|
+
"八": 8,
|
|
13
|
+
"九": 9,
|
|
14
|
+
"十": 10,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const WEEKDAY_OFFSET = {
|
|
18
|
+
"天": 0,
|
|
19
|
+
"日": 0,
|
|
20
|
+
"一": 1,
|
|
21
|
+
"二": 2,
|
|
22
|
+
"三": 3,
|
|
23
|
+
"四": 4,
|
|
24
|
+
"五": 5,
|
|
25
|
+
"六": 6,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function zhStringToNumber(text: string) {
|
|
29
|
+
let number = 0;
|
|
30
|
+
|
|
31
|
+
for (let i = 0; i < text.length; i++) {
|
|
32
|
+
const char = text[i];
|
|
33
|
+
if (char === "十") {
|
|
34
|
+
number = number === 0 ? NUMBER[char] : number * NUMBER[char];
|
|
35
|
+
} else {
|
|
36
|
+
number += NUMBER[char];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function zhStringToYear(text: string) {
|
|
44
|
+
let string = "";
|
|
45
|
+
|
|
46
|
+
for (let i = 0; i < text.length; i++) {
|
|
47
|
+
const char = text[i];
|
|
48
|
+
string = string + NUMBER[char];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return parseInt(string);
|
|
52
|
+
}
|