chrono-node 2.2.7 → 2.3.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.
Files changed (98) hide show
  1. package/README.md +25 -9
  2. package/benchmark/benchmark.js +4 -0
  3. package/dist/bundle.js +5047 -0
  4. package/dist/chrono.d.ts +7 -6
  5. package/dist/chrono.js +6 -5
  6. package/dist/common/casualReferences.d.ts +6 -6
  7. package/dist/common/casualReferences.js +16 -15
  8. package/dist/common/refiners/ForwardDateRefiner.js +1 -1
  9. package/dist/index.d.ts +7 -3
  10. package/dist/locales/de/constants.js +1 -1
  11. package/dist/locales/de/parsers/DECasualDateParser.js +2 -2
  12. package/dist/locales/en/constants.d.ts +1 -1
  13. package/dist/locales/en/constants.js +5 -5
  14. package/dist/locales/en/parsers/ENCasualDateParser.js +5 -5
  15. package/dist/locales/en/parsers/ENCasualTimeParser.js +1 -1
  16. package/dist/locales/en/parsers/ENMonthNameLittleEndianParser.js +6 -8
  17. package/dist/locales/en/parsers/ENRelativeDateFormatParser.js +3 -3
  18. package/dist/locales/en/parsers/ENTimeUnitAgoFormatParser.js +3 -3
  19. package/dist/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.js +1 -1
  20. package/dist/locales/en/parsers/ENTimeUnitLaterFormatParser.js +2 -2
  21. package/dist/locales/en/parsers/ENTimeUnitWithinFormatParser.js +1 -1
  22. package/dist/locales/fr/constants.js +1 -1
  23. package/dist/locales/fr/parsers/FRCasualDateParser.js +4 -4
  24. package/dist/locales/fr/parsers/FRTimeUnitAgoFormatParser.js +1 -1
  25. package/dist/locales/fr/parsers/FRTimeUnitRelativeFormatParser.js +1 -1
  26. package/dist/locales/fr/parsers/FRTimeUnitWithinFormatParser.js +1 -1
  27. package/dist/locales/ja/parsers/JPCasualDateParser.js +3 -3
  28. package/dist/locales/nl/constants.js +8 -5
  29. package/dist/locales/nl/index.js +12 -3
  30. package/dist/locales/nl/parsers/NLCasualDateParser.js +4 -4
  31. package/dist/locales/nl/parsers/NLRelativeDateFormatParser.d.ts +7 -0
  32. package/dist/locales/nl/parsers/NLRelativeDateFormatParser.js +57 -0
  33. package/dist/locales/nl/parsers/NLTimeExpressionParser.d.ts +1 -0
  34. package/dist/locales/nl/parsers/NLTimeExpressionParser.js +3 -0
  35. package/dist/locales/nl/parsers/NLTimeUnitAgoFormatParser.d.ts +9 -0
  36. package/dist/locales/nl/parsers/NLTimeUnitAgoFormatParser.js +23 -0
  37. package/dist/locales/nl/parsers/NLTimeUnitCasualRelativeFormatParser.d.ts +7 -0
  38. package/dist/locales/nl/parsers/NLTimeUnitCasualRelativeFormatParser.js +25 -0
  39. package/dist/locales/nl/parsers/NLTimeUnitLaterFormatParser.d.ts +9 -0
  40. package/dist/locales/nl/parsers/NLTimeUnitLaterFormatParser.js +22 -0
  41. package/dist/locales/nl/parsers/NLTimeUnitWithinFormatParser.js +1 -1
  42. package/dist/locales/pt/parsers/PTCasualDateParser.js +4 -4
  43. package/dist/main.js +1078 -0
  44. package/dist/results.d.ts +12 -5
  45. package/dist/results.js +40 -17
  46. package/dist/timezone.d.ts +194 -0
  47. package/dist/timezone.js +207 -0
  48. package/dist/utils/dayjs.js +0 -2
  49. package/dist/utils/pattern.js +1 -1
  50. package/package.json +3 -3
  51. package/src/chrono.ts +21 -8
  52. package/src/common/casualReferences.ts +17 -18
  53. package/src/common/refiners/ForwardDateRefiner.ts +1 -1
  54. package/src/index.ts +19 -3
  55. package/src/locales/de/constants.ts +1 -1
  56. package/src/locales/de/parsers/DECasualDateParser.ts +2 -2
  57. package/src/locales/en/constants.ts +5 -5
  58. package/src/locales/en/parsers/ENCasualDateParser.ts +5 -5
  59. package/src/locales/en/parsers/ENCasualTimeParser.ts +1 -1
  60. package/src/locales/en/parsers/ENMonthNameLittleEndianParser.ts +9 -10
  61. package/src/locales/en/parsers/ENRelativeDateFormatParser.ts +3 -3
  62. package/src/locales/en/parsers/ENTimeUnitAgoFormatParser.ts +3 -4
  63. package/src/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.ts +1 -1
  64. package/src/locales/en/parsers/ENTimeUnitLaterFormatParser.ts +2 -2
  65. package/src/locales/en/parsers/ENTimeUnitWithinFormatParser.ts +1 -1
  66. package/src/locales/fr/constants.ts +1 -1
  67. package/src/locales/fr/parsers/FRCasualDateParser.ts +4 -4
  68. package/src/locales/fr/parsers/FRTimeUnitAgoFormatParser.ts +1 -1
  69. package/src/locales/fr/parsers/FRTimeUnitRelativeFormatParser.ts +1 -1
  70. package/src/locales/fr/parsers/FRTimeUnitWithinFormatParser.ts +1 -1
  71. package/src/locales/ja/parsers/JPCasualDateParser.ts +3 -3
  72. package/src/locales/nl/constants.ts +11 -5
  73. package/src/locales/nl/index.ts +12 -3
  74. package/src/locales/nl/parsers/NLCasualDateParser.ts +4 -4
  75. package/src/locales/nl/parsers/NLRelativeDateFormatParser.ts +70 -0
  76. package/src/locales/nl/parsers/NLTimeExpressionParser.ts +4 -0
  77. package/src/locales/nl/parsers/NLTimeUnitAgoFormatParser.ts +26 -0
  78. package/src/locales/nl/parsers/NLTimeUnitCasualRelativeFormatParser.ts +27 -0
  79. package/src/locales/nl/parsers/NLTimeUnitLaterFormatParser.ts +27 -0
  80. package/src/locales/nl/parsers/NLTimeUnitWithinFormatParser.ts +1 -1
  81. package/src/locales/pt/parsers/PTCasualDateParser.ts +4 -4
  82. package/src/results.ts +52 -18
  83. package/src/timezone.ts +205 -0
  84. package/src/utils/dayjs.ts +0 -2
  85. package/src/utils/pattern.ts +1 -1
  86. package/test/en/en_month_name_little_endian.test.ts +10 -0
  87. package/test/en/en_relative.test.ts +30 -0
  88. package/test/en/en_slash.test.ts +11 -0
  89. package/test/en/en_timezone_exp.test.ts +7 -4
  90. package/test/en/en_weekday.test.ts +69 -25
  91. package/test/en/negative_cases.test.ts +2 -0
  92. package/test/nl/nl_relative.test.ts +212 -0
  93. package/test/nl/nl_time_units_ago.test.ts +243 -0
  94. package/test/nl/nl_time_units_casual_relative.test.ts +130 -0
  95. package/test/nl/nl_time_units_later.test.ts +250 -0
  96. package/test/result.test.ts +32 -13
  97. package/test/system_timezone.test.ts +100 -0
  98. package/test/test_util.ts +10 -7
@@ -1,19 +1,20 @@
1
- import { ParsingComponents } from "../results";
1
+ import { ParsingComponents, ReferenceWithTimezone } from "../results";
2
2
  import dayjs from "dayjs";
3
3
  import { assignSimilarDate, assignSimilarTime, assignTheNextDay, implySimilarTime } from "../utils/dayjs";
4
4
  import { Meridiem } from "../index";
5
5
 
6
- export function now(refDate: Date): ParsingComponents {
7
- const targetDate = dayjs(refDate);
8
- const component = new ParsingComponents(refDate, {});
6
+ export function now(reference: ReferenceWithTimezone): ParsingComponents {
7
+ const targetDate = dayjs(reference.instant);
8
+ const component = new ParsingComponents(reference, {});
9
9
  assignSimilarDate(component, targetDate);
10
10
  assignSimilarTime(component, targetDate);
11
+ component.assign("timezoneOffset", targetDate.utcOffset());
11
12
  return component;
12
13
  }
13
14
 
14
- export function today(refDate: Date): ParsingComponents {
15
- const targetDate = dayjs(refDate);
16
- const component = new ParsingComponents(refDate, {});
15
+ export function today(reference: ReferenceWithTimezone): ParsingComponents {
16
+ const targetDate = dayjs(reference.instant);
17
+ const component = new ParsingComponents(reference, {});
17
18
  assignSimilarDate(component, targetDate);
18
19
  implySimilarTime(component, targetDate);
19
20
  return component;
@@ -21,11 +22,10 @@ export function today(refDate: Date): ParsingComponents {
21
22
 
22
23
  /**
23
24
  * The previous day. Imply the same time.
24
- * @param refDate
25
25
  */
26
- export function yesterday(refDate: Date): ParsingComponents {
27
- let targetDate = dayjs(refDate);
28
- const component = new ParsingComponents(refDate, {});
26
+ export function yesterday(reference: ReferenceWithTimezone): ParsingComponents {
27
+ let targetDate = dayjs(reference.instant);
28
+ const component = new ParsingComponents(reference, {});
29
29
  targetDate = targetDate.add(-1, "day");
30
30
  assignSimilarDate(component, targetDate);
31
31
  implySimilarTime(component, targetDate);
@@ -34,18 +34,17 @@ export function yesterday(refDate: Date): ParsingComponents {
34
34
 
35
35
  /**
36
36
  * The following day with dayjs.assignTheNextDay()
37
- * @param refDate
38
37
  */
39
- export function tomorrow(refDate: Date): ParsingComponents {
40
- const targetDate = dayjs(refDate);
41
- const component = new ParsingComponents(refDate, {});
38
+ export function tomorrow(reference: ReferenceWithTimezone): ParsingComponents {
39
+ const targetDate = dayjs(reference.instant);
40
+ const component = new ParsingComponents(reference, {});
42
41
  assignTheNextDay(component, targetDate);
43
42
  return component;
44
43
  }
45
44
 
46
- export function tonight(refDate: Date, implyHour = 22): ParsingComponents {
47
- const targetDate = dayjs(refDate);
48
- const component = new ParsingComponents(refDate, {});
45
+ export function tonight(reference: ReferenceWithTimezone, implyHour = 22): ParsingComponents {
46
+ const targetDate = dayjs(reference.instant);
47
+ const component = new ParsingComponents(reference, {});
49
48
  component.imply("hour", implyHour);
50
49
  component.imply("meridiem", Meridiem.PM);
51
50
  assignSimilarDate(component, targetDate);
@@ -34,7 +34,7 @@ export default class ForwardDateRefiner implements Refiner {
34
34
  }
35
35
 
36
36
  if (result.start.isOnlyWeekdayComponent() && refMoment.isAfter(result.start.dayjs())) {
37
- if (refMoment.day() > result.start.get("weekday")) {
37
+ if (refMoment.day() >= result.start.get("weekday")) {
38
38
  refMoment = refMoment.day(result.start.get("weekday") + 7);
39
39
  } else {
40
40
  refMoment = refMoment.day(<number>result.start.get("weekday"));
package/src/index.ts CHANGED
@@ -14,7 +14,7 @@ export interface ParsingOption {
14
14
  /**
15
15
  * Additional timezone keywords for the parsers to recognize
16
16
  */
17
- timezones?: { string: number };
17
+ timezones?: { [tzKeyword: string]: number };
18
18
 
19
19
  /**
20
20
  * Internal debug event handler.
@@ -23,6 +23,22 @@ export interface ParsingOption {
23
23
  debug?: DebugHandler | DebugConsume;
24
24
  }
25
25
 
26
+ export interface ParsingReference {
27
+ /**
28
+ * Reference date. The instant (JavaScript Date object) when the input is written or mention.
29
+ * This effect date/time implication (e.g. weekday or time mentioning).
30
+ * (default = now)
31
+ */
32
+ instant?: Date;
33
+
34
+ /**
35
+ * Reference timezone. The timezone where the input is written or mention.
36
+ * Date/time implication will account the difference between input timezone and the current system timezone.
37
+ * (default = current timezone)
38
+ */
39
+ timezone?: string | number;
40
+ }
41
+
26
42
  /**
27
43
  * Parsed result or final output.
28
44
  * Each result object represents a date/time (or date/time-range) mentioning in the input.
@@ -104,13 +120,13 @@ export const casual = en.casual;
104
120
  /**
105
121
  * A shortcut for {@link en | chrono.en.casual.parse()}
106
122
  */
107
- export function parse(text: string, ref?: Date, option?: ParsingOption): ParsedResult[] {
123
+ export function parse(text: string, ref?: ParsingReference | Date, option?: ParsingOption): ParsedResult[] {
108
124
  return casual.parse(text, ref, option);
109
125
  }
110
126
 
111
127
  /**
112
128
  * A shortcut for {@link en | chrono.en.casual.parseDate()}
113
129
  */
114
- export function parseDate(text: string, ref?: Date, option?: ParsingOption): Date {
130
+ export function parseDate(text: string, ref?: ParsingReference | Date, option?: ParsingOption): Date {
115
131
  return casual.parseDate(text, ref, option);
116
132
  }
@@ -108,7 +108,7 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType } = {
108
108
 
109
109
  export const NUMBER_PATTERN = `(?:${matchAnyPattern(
110
110
  INTEGER_WORD_DICTIONARY
111
- )}|[0-9]+|[0-9]+\\.[0-9]+|half(?:\\s*an?)?|an?(?:\\s*few)?|few|several|a?\\s*couple\\s*(?:of)?)`;
111
+ )}|[0-9]+|[0-9]+\\.[0-9]+|half(?:\\s*an?)?|an?\\b(?:\\s*few)?|few|several|a?\\s*couple\\s*(?:of)?)`;
112
112
 
113
113
  export function parseNumberPattern(match: string): number {
114
114
  const num = match.toLowerCase();
@@ -29,11 +29,11 @@ export default class DECasualDateParser extends AbstractParserWithWordBoundaryCh
29
29
  let component = context.createParsingComponents();
30
30
  switch (dateKeyword) {
31
31
  case "jetzt":
32
- component = references.now(context.refDate);
32
+ component = references.now(context.reference);
33
33
  break;
34
34
 
35
35
  case "heute":
36
- component = references.today(context.refDate);
36
+ component = references.today(context.reference);
37
37
  break;
38
38
 
39
39
  case "morgen":
@@ -162,7 +162,7 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType } = {
162
162
 
163
163
  export const NUMBER_PATTERN = `(?:${matchAnyPattern(
164
164
  INTEGER_WORD_DICTIONARY
165
- )}|[0-9]+|[0-9]+\\.[0-9]+|half(?:\\s*an?)?|an?(?:\\s*few)?|few|several|a?\\s*couple\\s*(?:of)?)`;
165
+ )}|[0-9]+|[0-9]+\\.[0-9]+|half(?:\\s{0,2}an?)?|an?\\b(?:\\s{0,2}few)?|few|several|a?\\s{0,2}couple\\s{0,2}(?:of)?)`;
166
166
 
167
167
  export function parseNumberPattern(match: string): number {
168
168
  const num = match.toLowerCase();
@@ -198,7 +198,7 @@ export function parseOrdinalNumberPattern(match: string): number {
198
198
 
199
199
  //-----------------------------
200
200
 
201
- export const YEAR_PATTERN = `(?:[1-9][0-9]{0,3}\\s*(?:BE|AD|BC|BCE|CE)|[1-2][0-9]{3}|[5-9][0-9])`;
201
+ export const YEAR_PATTERN = `(?:[1-9][0-9]{0,3}\\s{0,2}(?:BE|AD|BC|BCE|CE)|[1-2][0-9]{3}|[5-9][0-9])`;
202
202
  export function parseYear(match: string): number {
203
203
  if (/BE/i.test(match)) {
204
204
  // Buddhist Era
@@ -224,10 +224,10 @@ export function parseYear(match: string): number {
224
224
 
225
225
  //-----------------------------
226
226
 
227
- const SINGLE_TIME_UNIT_PATTERN = `(${NUMBER_PATTERN})\\s{0,5}(${matchAnyPattern(TIME_UNIT_DICTIONARY)})\\s{0,5}`;
227
+ const SINGLE_TIME_UNIT_PATTERN = `(${NUMBER_PATTERN})\\s{0,3}(${matchAnyPattern(TIME_UNIT_DICTIONARY)})`;
228
228
  const SINGLE_TIME_UNIT_REGEX = new RegExp(SINGLE_TIME_UNIT_PATTERN, "i");
229
229
 
230
- export const TIME_UNITS_PATTERN = repeatedTimeunitPattern(`(?:(?:about|around)\\s*)?`, SINGLE_TIME_UNIT_PATTERN);
230
+ export const TIME_UNITS_PATTERN = repeatedTimeunitPattern(`(?:(?:about|around)\\s{0,3})?`, SINGLE_TIME_UNIT_PATTERN);
231
231
 
232
232
  export function parseTimeUnits(timeunitText): TimeUnits {
233
233
  const fragments = {};
@@ -235,7 +235,7 @@ export function parseTimeUnits(timeunitText): TimeUnits {
235
235
  let match = SINGLE_TIME_UNIT_REGEX.exec(remainingText);
236
236
  while (match) {
237
237
  collectDateTimeFragment(fragments, match);
238
- remainingText = remainingText.substring(match[0].length);
238
+ remainingText = remainingText.substring(match[0].length).trim();
239
239
  match = SINGLE_TIME_UNIT_REGEX.exec(remainingText);
240
240
  }
241
241
  return fragments;
@@ -19,21 +19,21 @@ export default class ENCasualDateParser extends AbstractParserWithWordBoundaryCh
19
19
 
20
20
  switch (lowerText) {
21
21
  case "now":
22
- return references.now(context.refDate);
22
+ return references.now(context.reference);
23
23
 
24
24
  case "today":
25
- return references.today(context.refDate);
25
+ return references.today(context.reference);
26
26
 
27
27
  case "yesterday":
28
- return references.yesterday(context.refDate);
28
+ return references.yesterday(context.reference);
29
29
 
30
30
  case "tomorrow":
31
31
  case "tmr":
32
32
  case "tmrw":
33
- return references.tomorrow(context.refDate);
33
+ return references.tomorrow(context.reference);
34
34
 
35
35
  case "tonight":
36
- return references.tonight(context.refDate);
36
+ return references.tonight(context.reference);
37
37
 
38
38
  default:
39
39
  if (lowerText.match(/last\s*night/)) {
@@ -4,7 +4,7 @@ import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/
4
4
  import dayjs from "dayjs";
5
5
  import { assignTheNextDay } from "../../../utils/dayjs";
6
6
 
7
- const PATTERN = /(?:this)?\s*(morning|afternoon|evening|night|midnight|noon)(?=\W|$)/i;
7
+ const PATTERN = /(?:this)?\s{0,3}(morning|afternoon|evening|night|midnight|noon)(?=\W|$)/i;
8
8
 
9
9
  export default class ENCasualTimeParser extends AbstractParserWithWordBoundaryChecking {
10
10
  innerPattern() {
@@ -7,20 +7,19 @@ import { ORDINAL_NUMBER_PATTERN, parseOrdinalNumberPattern } from "../constants"
7
7
  import { matchAnyPattern } from "../../../utils/pattern";
8
8
  import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary";
9
9
 
10
+ // prettier-ignore
10
11
  const PATTERN = new RegExp(
11
- "(?:on\\s*?)?" +
12
- `(${ORDINAL_NUMBER_PATTERN})` +
13
- "(?:\\s*" +
14
- "(?:to|\\-|\\–|until|through|till|\\s)\\s*" +
12
+ `(?:on\\s{0,3})?` +
15
13
  `(${ORDINAL_NUMBER_PATTERN})` +
14
+ `(?:` +
15
+ `\\s{0,3}(?:to|\\-|\\–|until|through|till)?\\s{0,3}` +
16
+ `(${ORDINAL_NUMBER_PATTERN})` +
16
17
  ")?" +
17
- "(?:-|/|\\s*(?:of)?\\s*)" +
18
- "(" +
19
- matchAnyPattern(MONTH_DICTIONARY) +
20
- ")" +
18
+ `(?:-|/|\\s{0,3}(?:of)?\\s{0,3})` +
19
+ `(${matchAnyPattern(MONTH_DICTIONARY)})` +
21
20
  "(?:" +
22
- "(?:-|/|,?\\s*)" +
23
- `(${YEAR_PATTERN}(?![^\\s]\\d))` +
21
+ `(?:-|/|,?\\s{0,3})` +
22
+ `(${YEAR_PATTERN}(?![^\\s]\\d))` +
24
23
  ")?" +
25
24
  "(?=\\W|$)",
26
25
  "i"
@@ -26,17 +26,17 @@ export default class ENRelativeDateFormatParser extends AbstractParserWithWordBo
26
26
  if (modifier == "next") {
27
27
  const timeUnits = {};
28
28
  timeUnits[timeunit] = 1;
29
- return ParsingComponents.createRelativeFromRefDate(context.refDate, timeUnits);
29
+ return ParsingComponents.createRelativeFromReference(context.reference, timeUnits);
30
30
  }
31
31
 
32
32
  if (modifier == "last" || modifier == "past") {
33
33
  const timeUnits = {};
34
34
  timeUnits[timeunit] = -1;
35
- return ParsingComponents.createRelativeFromRefDate(context.refDate, timeUnits);
35
+ return ParsingComponents.createRelativeFromReference(context.reference, timeUnits);
36
36
  }
37
37
 
38
38
  const components = context.createParsingComponents();
39
- let date = dayjs(context.refDate);
39
+ let date = dayjs(context.reference.instant);
40
40
 
41
41
  // This week
42
42
  if (unitWord.match(/week/i)) {
@@ -4,9 +4,8 @@ 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 + ")" + "(?:ago|before|earlier)(?=(?:\\W|$))", "i");
8
-
9
- const STRICT_PATTERN = new RegExp("" + "(" + TIME_UNITS_PATTERN + ")" + "ago(?=(?:\\W|$))", "i");
7
+ const PATTERN = new RegExp(`(${TIME_UNITS_PATTERN})\\s{0,5}(?:ago|before|earlier)(?=(?:\\W|$))`, "i");
8
+ const STRICT_PATTERN = new RegExp(`(${TIME_UNITS_PATTERN})\\s{0,5}ago(?=(?:\\W|$))`, "i");
10
9
 
11
10
  export default class ENTimeUnitAgoFormatParser extends AbstractParserWithWordBoundaryChecking {
12
11
  constructor(private strictMode: boolean) {
@@ -21,6 +20,6 @@ export default class ENTimeUnitAgoFormatParser extends AbstractParserWithWordBou
21
20
  const timeUnits = parseTimeUnits(match[1]);
22
21
  const outputTimeUnits = reverseTimeUnits(timeUnits);
23
22
 
24
- return ParsingComponents.createRelativeFromRefDate(context.refDate, outputTimeUnits);
23
+ return ParsingComponents.createRelativeFromReference(context.reference, outputTimeUnits);
25
24
  }
26
25
  }
@@ -22,6 +22,6 @@ export default class ENTimeUnitCasualRelativeFormatParser extends AbstractParser
22
22
  break;
23
23
  }
24
24
 
25
- return ParsingComponents.createRelativeFromRefDate(context.refDate, timeUnits);
25
+ return ParsingComponents.createRelativeFromReference(context.reference, timeUnits);
26
26
  }
27
27
  }
@@ -4,7 +4,7 @@ import { ParsingComponents } from "../../../results";
4
4
  import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary";
5
5
 
6
6
  const PATTERN = new RegExp(
7
- "" + "(" + TIME_UNITS_PATTERN + ")" + "(later|after|from now|henceforth|forward|out)" + "(?=(?:\\W|$))",
7
+ `(${TIME_UNITS_PATTERN})\\s{0,5}(?:later|after|from now|henceforth|forward|out)` + "(?=(?:\\W|$))",
8
8
  "i"
9
9
  );
10
10
 
@@ -22,6 +22,6 @@ export default class ENTimeUnitLaterFormatParser extends AbstractParserWithWordB
22
22
 
23
23
  innerExtract(context: ParsingContext, match: RegExpMatchArray) {
24
24
  const fragments = parseTimeUnits(match[GROUP_NUM_TIMEUNITS]);
25
- return ParsingComponents.createRelativeFromRefDate(context.refDate, fragments);
25
+ return ParsingComponents.createRelativeFromReference(context.reference, fragments);
26
26
  }
27
27
  }
@@ -21,6 +21,6 @@ export default class ENTimeUnitWithinFormatParser extends AbstractParserWithWord
21
21
 
22
22
  innerExtract(context: ParsingContext, match: RegExpMatchArray): ParsingComponents {
23
23
  const timeUnits = parseTimeUnits(match[1]);
24
- return ParsingComponents.createRelativeFromRefDate(context.refDate, timeUnits);
24
+ return ParsingComponents.createRelativeFromReference(context.reference, timeUnits);
25
25
  }
26
26
  }
@@ -105,7 +105,7 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType | QUnitType } =
105
105
 
106
106
  export const NUMBER_PATTERN = `(?:${matchAnyPattern(
107
107
  INTEGER_WORD_DICTIONARY
108
- )}|[0-9]+|[0-9]+\\.[0-9]+|une?|quelques?|demi-?)`;
108
+ )}|[0-9]+|[0-9]+\\.[0-9]+|une?\\b|quelques?|demi-?)`;
109
109
 
110
110
  export function parseNumberPattern(match: string): number {
111
111
  const num = match.toLowerCase();
@@ -18,16 +18,16 @@ export default class FRCasualDateParser extends AbstractParserWithWordBoundaryCh
18
18
 
19
19
  switch (lowerText) {
20
20
  case "maintenant":
21
- return references.now(context.refDate);
21
+ return references.now(context.reference);
22
22
 
23
23
  case "aujourd'hui":
24
- return references.today(context.refDate);
24
+ return references.today(context.reference);
25
25
 
26
26
  case "hier":
27
- return references.yesterday(context.refDate);
27
+ return references.yesterday(context.reference);
28
28
 
29
29
  case "demain":
30
- return references.tomorrow(context.refDate);
30
+ return references.tomorrow(context.reference);
31
31
 
32
32
  default:
33
33
  if (lowerText.match(/cette\s*nuit/)) {
@@ -17,6 +17,6 @@ export default class FRTimeUnitAgoFormatParser extends AbstractParserWithWordBou
17
17
  const timeUnits = parseTimeUnits(match[1]);
18
18
  const outputTimeUnits = reverseTimeUnits(timeUnits);
19
19
 
20
- return ParsingComponents.createRelativeFromRefDate(context.refDate, outputTimeUnits);
20
+ return ParsingComponents.createRelativeFromReference(context.reference, outputTimeUnits);
21
21
  }
22
22
  }
@@ -38,6 +38,6 @@ export default class FRTimeUnitAgoFormatParser extends AbstractParserWithWordBou
38
38
  timeUnits = reverseTimeUnits(timeUnits);
39
39
  }
40
40
 
41
- return ParsingComponents.createRelativeFromRefDate(context.refDate, timeUnits);
41
+ return ParsingComponents.createRelativeFromReference(context.reference, timeUnits);
42
42
  }
43
43
  }
@@ -10,6 +10,6 @@ export default class FRTimeUnitWithinFormatParser extends AbstractParserWithWord
10
10
 
11
11
  innerExtract(context: ParsingContext, match: RegExpMatchArray): ParsingComponents {
12
12
  const timeUnits = parseTimeUnits(match[1]);
13
- return ParsingComponents.createRelativeFromRefDate(context.refDate, timeUnits);
13
+ return ParsingComponents.createRelativeFromReference(context.reference, timeUnits);
14
14
  }
15
15
  }
@@ -18,14 +18,14 @@ export default class JPCasualDateParser implements Parser {
18
18
 
19
19
  switch (text) {
20
20
  case "昨日":
21
- return references.yesterday(context.refDate);
21
+ return references.yesterday(context.reference);
22
22
 
23
23
  case "明日":
24
- return references.tomorrow(context.refDate);
24
+ return references.tomorrow(context.reference);
25
25
 
26
26
  case "今日":
27
27
  case "当日":
28
- return references.today(context.refDate);
28
+ return references.today(context.reference);
29
29
  }
30
30
 
31
31
  if (text == "今夜" || text == "今夕" || text == "今晩") {
@@ -141,11 +141,14 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType } = {
141
141
  min: "minute",
142
142
  mins: "minute",
143
143
  minute: "minute",
144
+ minuut: "minute",
144
145
  minuten: "minute",
146
+ minuutje: "minute",
145
147
  h: "hour",
146
148
  hr: "hour",
147
149
  hrs: "hour",
148
150
  uur: "hour",
151
+ u: "hour",
149
152
  uren: "hour",
150
153
  dag: "d",
151
154
  dagen: "d",
@@ -160,18 +163,21 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType } = {
160
163
 
161
164
  //-----------------------------
162
165
 
163
- export const NUMBER_PATTERN = `(?:${matchAnyPattern(INTEGER_WORD_DICTIONARY)}|[0-9]+|[0-9]+\\.[0-9]+|een?|halve?)`;
166
+ export const NUMBER_PATTERN = `(?:${matchAnyPattern(
167
+ INTEGER_WORD_DICTIONARY
168
+ )}|[0-9]+|[0-9]+[\\.,][0-9]+|halve?|half|paar)`;
164
169
 
165
170
  export function parseNumberPattern(match: string): number {
166
171
  const num = match.toLowerCase();
167
172
  if (INTEGER_WORD_DICTIONARY[num] !== undefined) {
168
173
  return INTEGER_WORD_DICTIONARY[num];
169
- } else if (num === "een") {
170
- return 1;
171
- } else if (num.match(/halve?/)) {
174
+ } else if (num === "paar") {
175
+ return 2;
176
+ } else if (num === "half" || num.match(/halve?/)) {
172
177
  return 0.5;
173
178
  }
174
- return parseFloat(num);
179
+ // Replace "," with "." to support some European languages
180
+ return parseFloat(num.replace(",", "."));
175
181
  }
176
182
 
177
183
  //-----------------------------
@@ -20,6 +20,10 @@ import NLSlashMonthFormatParser from "./parsers/NLSlashMonthFormatParser";
20
20
  import NLTimeExpressionParser from "./parsers/NLTimeExpressionParser";
21
21
  import NLCasualYearMonthDayParser from "./parsers/NLCasualYearMonthDayParser";
22
22
  import NLCasualDateTimeParser from "./parsers/NLCasualDateTimeParser";
23
+ import NLTimeUnitCasualRelativeFormatParser from "./parsers/NLTimeUnitCasualRelativeFormatParser";
24
+ import NLRelativeDateFormatParser from "./parsers/NLRelativeDateFormatParser";
25
+ import NLTimeUnitAgoFormatParser from "./parsers/NLTimeUnitAgoFormatParser";
26
+ import NLTimeUnitLaterFormatParser from "./parsers/NLTimeUnitLaterFormatParser";
23
27
 
24
28
  // Shortcuts
25
29
  export const casual = new Chrono(createCasualConfiguration());
@@ -38,6 +42,9 @@ export function createCasualConfiguration(littleEndian = true): Configuration {
38
42
  option.parsers.unshift(new NLCasualDateParser());
39
43
  option.parsers.unshift(new NLCasualTimeParser());
40
44
  option.parsers.unshift(new NLCasualDateTimeParser());
45
+ option.parsers.unshift(new NLMonthNameParser());
46
+ option.parsers.unshift(new NLRelativeDateFormatParser());
47
+ option.parsers.unshift(new NLTimeUnitCasualRelativeFormatParser());
41
48
  return option;
42
49
  }
43
50
 
@@ -49,13 +56,15 @@ export function createConfiguration(strictMode = true, littleEndian = true): Con
49
56
  {
50
57
  parsers: [
51
58
  new SlashDateFormatParser(littleEndian),
59
+ new NLTimeUnitWithinFormatParser(),
52
60
  new NLMonthNameMiddleEndianParser(),
53
61
  new NLMonthNameParser(),
54
- new NLTimeExpressionParser(),
55
- new NLTimeUnitWithinFormatParser(),
56
- new NLSlashMonthFormatParser(),
57
62
  new NLWeekdayParser(),
58
63
  new NLCasualYearMonthDayParser(),
64
+ new NLSlashMonthFormatParser(),
65
+ new NLTimeExpressionParser(strictMode),
66
+ new NLTimeUnitAgoFormatParser(strictMode),
67
+ new NLTimeUnitLaterFormatParser(strictMode),
59
68
  ],
60
69
  refiners: [new NLMergeDateTimeRefiner(), new NLMergeDateRangeRefiner()],
61
70
  },
@@ -14,17 +14,17 @@ export default class NLCasualDateParser extends AbstractParserWithWordBoundaryCh
14
14
 
15
15
  switch (lowerText) {
16
16
  case "nu":
17
- return references.now(context.refDate);
17
+ return references.now(context.reference);
18
18
 
19
19
  case "vandaag":
20
- return references.today(context.refDate);
20
+ return references.today(context.reference);
21
21
 
22
22
  case "morgen":
23
23
  case "morgend":
24
- return references.tomorrow(context.refDate);
24
+ return references.tomorrow(context.reference);
25
25
 
26
26
  case "gisteren":
27
- return references.yesterday(context.refDate);
27
+ return references.yesterday(context.reference);
28
28
  }
29
29
 
30
30
  return component;
@@ -0,0 +1,70 @@
1
+ import { TIME_UNIT_DICTIONARY } from "../constants";
2
+ import { ParsingContext } from "../../../chrono";
3
+ import { ParsingComponents } from "../../../results";
4
+ import dayjs from "dayjs";
5
+ import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary";
6
+ import { matchAnyPattern } from "../../../utils/pattern";
7
+
8
+ const PATTERN = new RegExp(
9
+ `(dit|deze|komende|volgend|volgende|afgelopen|vorige)\\s*(${matchAnyPattern(TIME_UNIT_DICTIONARY)})(?=\\s*)` +
10
+ "(?=\\W|$)",
11
+ "i"
12
+ );
13
+
14
+ const MODIFIER_WORD_GROUP = 1;
15
+ const RELATIVE_WORD_GROUP = 2;
16
+
17
+ export default class NLRelativeDateFormatParser extends AbstractParserWithWordBoundaryChecking {
18
+ innerPattern(): RegExp {
19
+ return PATTERN;
20
+ }
21
+
22
+ innerExtract(context: ParsingContext, match: RegExpMatchArray): ParsingComponents {
23
+ const modifier = match[MODIFIER_WORD_GROUP].toLowerCase();
24
+ const unitWord = match[RELATIVE_WORD_GROUP].toLowerCase();
25
+ const timeunit = TIME_UNIT_DICTIONARY[unitWord];
26
+
27
+ if (modifier == "volgend" || modifier == "volgende" || modifier == "komende") {
28
+ const timeUnits = {};
29
+ timeUnits[timeunit] = 1;
30
+ return ParsingComponents.createRelativeFromReference(context.reference, timeUnits);
31
+ }
32
+
33
+ if (modifier == "afgelopen" || modifier == "vorige") {
34
+ const timeUnits = {};
35
+ timeUnits[timeunit] = -1;
36
+ return ParsingComponents.createRelativeFromReference(context.reference, timeUnits);
37
+ }
38
+
39
+ const components = context.createParsingComponents();
40
+ let date = dayjs(context.reference.instant);
41
+
42
+ // This week
43
+ if (unitWord.match(/week/i)) {
44
+ date = date.add(-date.get("d"), "d");
45
+ components.imply("day", date.date());
46
+ components.imply("month", date.month() + 1);
47
+ components.imply("year", date.year());
48
+ }
49
+
50
+ // This month
51
+ else if (unitWord.match(/maand/i)) {
52
+ date = date.add(-date.date() + 1, "d");
53
+ components.imply("day", date.date());
54
+ components.assign("year", date.year());
55
+ components.assign("month", date.month() + 1);
56
+ }
57
+
58
+ // This year
59
+ else if (unitWord.match(/jaar/i)) {
60
+ date = date.add(-date.date() + 1, "d");
61
+ date = date.add(-date.month(), "month");
62
+
63
+ components.imply("day", date.date());
64
+ components.imply("month", date.month() + 1);
65
+ components.assign("year", date.year());
66
+ }
67
+
68
+ return components;
69
+ }
70
+ }
@@ -11,6 +11,10 @@ export default class NLTimeExpressionParser extends AbstractTimeExpressionParser
11
11
  return "\\s*(?:\\-|\\–|\\~|\\〜|om|\\?)\\s*";
12
12
  }
13
13
 
14
+ primarySuffix(): string {
15
+ return "(?:\\s*(?:uur))?(?!/)(?=\\W|$)";
16
+ }
17
+
14
18
  extractPrimaryTimeComponents(context: ParsingContext, match: RegExpMatchArray): ParsingComponents | null {
15
19
  // This looks more like a year e.g. 2020
16
20
  if (match[0].match(/^\s*\d{4}\s*$/)) {
@@ -0,0 +1,26 @@
1
+ import { ParsingContext } from "../../../chrono";
2
+ import { parseTimeUnits, TIME_UNITS_PATTERN } from "../constants";
3
+ import { ParsingComponents } from "../../../results";
4
+ import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary";
5
+ import { reverseTimeUnits } from "../../../utils/timeunits";
6
+
7
+ const PATTERN = new RegExp("" + "(" + TIME_UNITS_PATTERN + ")" + "(?:geleden|voor|eerder)(?=(?:\\W|$))", "i");
8
+
9
+ const STRICT_PATTERN = new RegExp("" + "(" + TIME_UNITS_PATTERN + ")" + "geleden(?=(?:\\W|$))", "i");
10
+
11
+ export default class NLTimeUnitAgoFormatParser extends AbstractParserWithWordBoundaryChecking {
12
+ constructor(private strictMode: boolean) {
13
+ super();
14
+ }
15
+
16
+ innerPattern(): RegExp {
17
+ return this.strictMode ? STRICT_PATTERN : PATTERN;
18
+ }
19
+
20
+ innerExtract(context: ParsingContext, match: RegExpMatchArray) {
21
+ const timeUnits = parseTimeUnits(match[1]);
22
+ const outputTimeUnits = reverseTimeUnits(timeUnits);
23
+
24
+ return ParsingComponents.createRelativeFromReference(context.reference, outputTimeUnits);
25
+ }
26
+ }