From 464bfb9db8c18fc292492be684670db92944d092 Mon Sep 17 00:00:00 2001 From: Georg Mayr-Duffner Date: Sun, 6 Mar 2022 20:26:20 +0100 Subject: [PATCH 1/5] [DE] Add ordinal number parsing --- src/locales/de/constants.ts | 166 ++++++++++++++++++ .../parsers/DEMonthNameLittleEndianParser.ts | 12 +- test/de/de_month_name_little_endian.test.ts | 43 +++++ 3 files changed, 217 insertions(+), 4 deletions(-) diff --git a/src/locales/de/constants.ts b/src/locales/de/constants.ts index c6f45f97..bff41c84 100644 --- a/src/locales/de/constants.ts +++ b/src/locales/de/constants.ts @@ -86,6 +86,159 @@ export const INTEGER_WORD_DICTIONARY: { [word: string]: number } = { "zwoelf": 12, }; +export const ORDINAL_WORD_DICTIONARY: { [word: string]: number } = { + erste: 1, + ersten: 1, + erster: 1, + erstes: 1, + zweite: 2, + zweiten: 2, + zweiter: 2, + zweites: 2, + dritte: 3, + dritten: 3, + dritter: 3, + drittes: 3, + vierte: 4, + vierten: 4, + fünfte: 5, + fünften: 5, + fünfter: 5, + fünftes: 5, + fuenfte: 5, + fuenften: 5, + fuenfter: 5, + fuenftes: 5, + sechste: 6, + sechsten: 6, + sechster: 6, + sechstes: 6, + siebte: 7, + siebten: 7, + siebter: 7, + siebtes: 7, + siebente: 7, + siebenten: 7, + siebenter: 7, + siebentes: 7, + achte: 8, + achten: 8, + achter: 8, + achtes: 8, + neunte: 9, + neunten: 9, + neunter: 9, + neuntes: 9, + zehnte: 10, + zehnten: 10, + zehnter: 10, + zehntes: 10, + elfte: 11, + elften: 11, + elfter: 11, + elftes: 11, + zwölfte: 12, + zwölften: 12, + zwölfter: 12, + zwölftes: 12, + zwoelfte: 12, + zwoelften: 12, + zwoelfter: 12, + zwoelftes: 12, + dreizehnte: 13, + dreizehnten: 13, + dreizehnter: 13, + dreizehntes: 13, + vierzehnte: 14, + vierzehnten: 14, + vierzehnter: 14, + vierzehntes: 14, + fünfzehnte: 15, + fünfzehnten: 15, + fünfzehnter: 15, + fünfzehntes: 15, + fuenfzehnte: 15, + fuenfzehnten: 15, + fuenfzehnter: 15, + fuenfzehntes: 15, + sechzehnte: 16, + sechzehnten: 16, + sechzehnter: 16, + sechzehntes: 16, + siebzehnte: 17, + siebzehnten: 17, + siebzehnter: 17, + siebzehntes: 17, + achtzehnte: 18, + achtzehnten: 18, + achtzehnter: 18, + achtzehntes: 18, + neunzehnte: 19, + neunzehnten: 19, + neunzehnter: 19, + neunzehntes: 19, + zwanzigste: 20, + zwanzigsten: 20, + zwanzigster: 20, + zwanzigstes: 20, + einundzwanzigste: 21, + einundzwanzigsten: 21, + einundzwanzigster: 21, + einundzwanzigstes: 21, + zweiundzwanzigste: 22, + zweiundzwanzigsten: 22, + zweiundzwanzigster: 22, + zweiundzwanzigstes: 22, + dreiundzwanzigste: 23, + dreiundzwanzigsten: 23, + dreiundzwanzigster: 23, + dreiundzwanzigstes: 23, + vierundzwanzigste: 24, + vierundzwanzigsten: 24, + vierundzwanzigster: 24, + vierundzwanzigstes: 24, + fünfundzwanzigste: 25, + fünfundzwanzigsten: 25, + fünfundzwanzigster: 25, + fünfundzwanzigstes: 25, + fuenfundzwanzigste: 25, + fuenfundzwanzigsten: 25, + fuenfundzwanzigster: 25, + fuenfundzwanzigstes: 25, + sechsundzwanzigste: 26, + sechsundzwanzigsten: 26, + sechsundzwanzigster: 26, + sechsundzwanzigstes: 26, + siebenundzwanzigste: 27, + siebenundzwanzigsten: 27, + siebenundzwanzigster: 27, + siebenundzwanzigstes: 27, + achtundzanzigste: 28, + achtundzanzigsten: 28, + achtundzanzigster: 28, + achtundzanzigstes: 28, + neundundzwanzigste: 29, + neundundzwanzigsten: 29, + neundundzwanzigster: 29, + neundundzwanzigstes: 29, + dreißigste: 30, + dreißigsten: 30, + dreißigster: 30, + dreißigstes: 30, + dreissigste: 30, + dreissigsten: 30, + dreissigster: 30, + dreissigstes: 30, + einunddreißigste: 31, + einunddreißigsten: 31, + einunddreißigster: 31, + einunddreißigstes: 31, + einunddreissigste: 31, + einunddreissigsten: 31, + einunddreissigster: 31, + einunddreissigstes: 31, +}; + export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType | QUnitType } = { sek: "second", sekunde: "second", @@ -146,6 +299,19 @@ export function parseNumberPattern(match: string): number { //----------------------------- +export const ORDINAL_NUMBER_PATTERN = `(?:${matchAnyPattern(ORDINAL_WORD_DICTIONARY)}|[0-9]{1,2}\\.?(?:te(?:n|r|s)?)?)`; +export function parseOrdinalNumberPattern(match: string): number { + let num = match.toLowerCase(); + if (ORDINAL_WORD_DICTIONARY[num] !== undefined) { + return ORDINAL_WORD_DICTIONARY[num]; + } + + num = num.replace(/(?:\\.?(?:te(?:n|r|s)?))$/i, ""); + return parseInt(num); +} + +//----------------------------- + 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\\.?)?)`; export function parseYear(match: string): number { if (/v/i.test(match)) { diff --git a/src/locales/de/parsers/DEMonthNameLittleEndianParser.ts b/src/locales/de/parsers/DEMonthNameLittleEndianParser.ts index 133b2737..13832f52 100644 --- a/src/locales/de/parsers/DEMonthNameLittleEndianParser.ts +++ b/src/locales/de/parsers/DEMonthNameLittleEndianParser.ts @@ -3,14 +3,18 @@ import { ParsingResult } from "../../../results"; import { findYearClosestToRef } from "../../../calculation/years"; import { MONTH_DICTIONARY } from "../constants"; import { YEAR_PATTERN, parseYear } from "../constants"; +import { ORDINAL_NUMBER_PATTERN, parseOrdinalNumberPattern } from "../constants"; import { matchAnyPattern } from "../../../utils/pattern"; import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary"; const PATTERN = new RegExp( "(?:am\\s*?)?" + "(?:den\\s*?)?" + - `([0-9]{1,2})\\.` + - `(?:\\s*(?:bis(?:\\s*(?:am|zum))?|\\-|\\–|\\s)\\s*([0-9]{1,2})\\.?)?\\s*` + + `(${ORDINAL_NUMBER_PATTERN})` + + `(?:` + + `\\s*(?:bis(?:\\s*(?:am|zum))?|\\-|\\–|\\s)?\\s*` + + `(${ORDINAL_NUMBER_PATTERN})` + + ")?\\s*" + `(${matchAnyPattern(MONTH_DICTIONARY)})` + `(?:(?:-|/|,?\\s*)(${YEAR_PATTERN}(?![^\\s]\\d)))?` + `(?=\\W|$)`, @@ -31,7 +35,7 @@ export default class DEMonthNameLittleEndianParser extends AbstractParserWithWor const result = context.createParsingResult(match.index, match[0]); const month = MONTH_DICTIONARY[match[MONTH_NAME_GROUP].toLowerCase()]; - const day = parseInt(match[DATE_GROUP]); + const day = parseOrdinalNumberPattern(match[DATE_GROUP]); if (day > 31) { // e.g. "[96 Aug]" => "9[6 Aug]", we need to shift away from the next number match.index = match.index + match[DATE_GROUP].length; @@ -50,7 +54,7 @@ export default class DEMonthNameLittleEndianParser extends AbstractParserWithWor } if (match[DATE_TO_GROUP]) { - const endDate = parseInt(match[DATE_TO_GROUP]); + const endDate = parseOrdinalNumberPattern(match[DATE_TO_GROUP]); result.end = result.start.clone(); result.end.assign("day", endDate); diff --git a/test/de/de_month_name_little_endian.test.ts b/test/de/de_month_name_little_endian.test.ts index 33a4d561..a3c6235a 100644 --- a/test/de/de_month_name_little_endian.test.ts +++ b/test/de/de_month_name_little_endian.test.ts @@ -77,6 +77,18 @@ test("Test - Single expression", function () { expect(result.start).toBeDate(new Date(2012, 8 - 1, 10, 12)); }); + testSingleCase(chrono.de, "Die Deadline ist am zehnten August", new Date(2012, 7, 10), (result) => { + expect(result.index).toBe(17); + expect(result.text).toBe("am zehnten August"); + + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(8); + expect(result.start.get("day")).toBe(10); + + expect(result.start).toBeDate(new Date(2012, 8 - 1, 10, 12)); + }); + testSingleCase(chrono.de, "Die Deadline ist am Dienstag, den 10. Januar", new Date(2012, 7, 10), (result) => { expect(result.index).toBe(17); expect(result.text).toBe("am Dienstag, den 10. Januar"); @@ -167,6 +179,25 @@ test("Test - Range expression", function () { expect(result.end).toBeDate(new Date(2012, 10 - 1, 22, 12)); }); + testSingleCase(chrono.de, "zehnter bis zweiundzwanzigster Oktober 2012", new Date(2012, 7, 10), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("zehnter bis zweiundzwanzigster Oktober 2012"); + + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(10); + expect(result.start.get("day")).toBe(10); + + expect(result.start).toBeDate(new Date(2012, 10 - 1, 10, 12)); + + expect(result.end).not.toBeNull(); + expect(result.end.get("year")).toBe(2012); + expect(result.end.get("month")).toBe(10); + expect(result.end.get("day")).toBe(22); + + expect(result.end).toBeDate(new Date(2012, 10 - 1, 22, 12)); + }); + testSingleCase(chrono.de, "10. Oktober - 12. Dezember", new Date(2012, 7, 10), (result) => { expect(result.index).toBe(0); expect(result.text).toBe("10. Oktober - 12. Dezember"); @@ -216,6 +247,18 @@ test("Test - Range expression", function () { expect(result.start).toBeDate(new Date(2012, 1 - 1, 10, 12)); }); + + testSingleCase(chrono.de, "zehnter jänner 2012", new Date(2012, 7, 10), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(1); + expect(result.start.get("day")).toBe(10); + + expect(result.index).toBe(0); + expect(result.text).toBe("zehnter jänner 2012"); + + expect(result.start).toBeDate(new Date(2012, 1 - 1, 10, 12)); + }); }); test("Test - Combined expression", function () { From 420ef5eb0b05961f27cfbf2cc0a14eee5e7c9524 Mon Sep 17 00:00:00 2001 From: Georg Mayr-Duffner Date: Thu, 10 Mar 2022 23:14:00 +0100 Subject: [PATCH 2/5] [DE] Add abbreviation for day --- src/locales/de/constants.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/locales/de/constants.ts b/src/locales/de/constants.ts index bff41c84..bffe1e67 100644 --- a/src/locales/de/constants.ts +++ b/src/locales/de/constants.ts @@ -250,6 +250,7 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType | QUnitType } = std: "hour", stunde: "hour", stunden: "hour", + d: "d", tag: "d", tage: "d", tagen: "d", From f14d33e5e5d7c7e592663d3e9bd825ba1459310d Mon Sep 17 00:00:00 2001 From: Georg Mayr-Duffner Date: Thu, 10 Mar 2022 23:16:42 +0100 Subject: [PATCH 3/5] [DE] Localise number and units patterns --- src/locales/de/constants.ts | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/locales/de/constants.ts b/src/locales/de/constants.ts index bffe1e67..326707ae 100644 --- a/src/locales/de/constants.ts +++ b/src/locales/de/constants.ts @@ -277,25 +277,31 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: OpUnitType | QUnitType } = export const NUMBER_PATTERN = `(?:${matchAnyPattern( INTEGER_WORD_DICTIONARY -)}|[0-9]+|[0-9]+\\.[0-9]+|half(?:\\s*an?)?|an?\\b(?:\\s*few)?|few|several|a?\\s*couple\\s*(?:of)?)`; +)}|[0-9]+|[0-9]+,[0-9]+|(?:ein(?:e(?:m|n|r|s)?)?\\s*)?(?:halb(?:e(?:n|r)?)?|(?:drei\\s?)?viertel|vtl\\.?)|ein\\s+paar|einige(?:r|n)?|mehrere(?:r|n)?|wenige(?:r|n)?|ein(?:e(?:m|n|r|s)?)?)`; export function parseNumberPattern(match: string): number { const num = match.toLowerCase(); if (INTEGER_WORD_DICTIONARY[num] !== undefined) { return INTEGER_WORD_DICTIONARY[num]; - } else if (num === "a" || num === "an") { + } else if (num === "ein" || num === "einem" || num === "einen" || num === "einer" || num === "eines") { return 1; - } else if (num.match(/few/)) { + } else if (num.match(/wenige/)) { return 3; - } else if (num.match(/half/)) { + } else if (num.match(/halb/)) { return 0.5; - } else if (num.match(/couple/)) { + } else if (num.match(/drei\s?viertel/)) { + return 0.75; + } else if (num.match(/viertel|vtl/)) { + return 0.25; + } else if (num.match(/paar/)) { return 2; - } else if (num.match(/several/)) { + } else if (num.match(/einige/)) { + return 5; + } else if (num.match(/mehrere/)) { return 7; } - return parseFloat(num); + return parseFloat(num.replace(",", ".")); } //----------------------------- @@ -339,7 +345,10 @@ export function parseYear(match: string): number { const SINGLE_TIME_UNIT_PATTERN = `(${NUMBER_PATTERN})\\s{0,5}(${matchAnyPattern(TIME_UNIT_DICTIONARY)})\\s{0,5}`; const SINGLE_TIME_UNIT_REGEX = new RegExp(SINGLE_TIME_UNIT_PATTERN, "i"); -export const TIME_UNITS_PATTERN = repeatedTimeunitPattern("", SINGLE_TIME_UNIT_PATTERN); +export const TIME_UNITS_PATTERN = repeatedTimeunitPattern( + `(?:(?:etwa|ungefähr|ca\\.?)\\s{0,3})?`, + SINGLE_TIME_UNIT_PATTERN +); export function parseTimeUnits(timeunitText): TimeUnits { const fragments = {}; From fdda9ddbf2ce07ee641763f326f7f114e8262f38 Mon Sep 17 00:00:00 2001 From: Georg Mayr-Duffner Date: Thu, 10 Mar 2022 23:18:10 +0100 Subject: [PATCH 4/5] Correct class name --- src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts b/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts index 5ebd19d8..0db49523 100644 --- a/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts +++ b/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts @@ -5,7 +5,7 @@ import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/ import { reverseTimeUnits } from "../../../utils/timeunits"; import { matchAnyPattern } from "../../../utils/pattern"; -export default class DETimeUnitAgoFormatParser extends AbstractParserWithWordBoundaryChecking { +export default class DETimeUnitRelativeFormatParser extends AbstractParserWithWordBoundaryChecking { constructor() { super(); } From 4c4a4136c6ac4ccfa02e0b5e11dea48416727a13 Mon Sep 17 00:00:00 2001 From: Georg Mayr-Duffner Date: Thu, 10 Mar 2022 23:19:54 +0100 Subject: [PATCH 5/5] [DE] Improve time units ago and later --- .../parsers/DETimeUnitRelativeFormatParser.ts | 30 +- test/de/de_time_units_ago.test.ts | 332 ++++++++++++++++++ test/de/de_time_units_later.test.ts | 151 ++++++++ 3 files changed, 504 insertions(+), 9 deletions(-) create mode 100644 test/de/de_time_units_ago.test.ts create mode 100644 test/de/de_time_units_later.test.ts diff --git a/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts b/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts index 0db49523..a051bd64 100644 --- a/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts +++ b/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts @@ -12,28 +12,40 @@ export default class DETimeUnitRelativeFormatParser extends AbstractParserWithWo innerPattern(): RegExp { return new RegExp( - `(?:\\s*((?:nächste|kommende|folgende|letzte|vergangene|vorige|vor(?:her|an)gegangene)(?:s|n|m|r)?|vor|in)\\s*)?` + + `(?:((?:(?:über)(?:über)nächste|kommende|folgende|(?:vor)?(?:vor)?letzte|vergangene|vorige|vor(?:her|an)gegangene)(?:s|n|m|r)?|vor|in|nach|ab\\sjetzt(?:\\sin)?)\\s*)?` + `(${NUMBER_PATTERN})?` + `(?:\\s*(nächste|kommende|folgende|letzte|vergangene|vorige|vor(?:her|an)gegangene)(?:s|n|m|r)?)?` + - `\\s*(${matchAnyPattern(TIME_UNIT_DICTIONARY)})`, + `\\s*(${matchAnyPattern(TIME_UNIT_DICTIONARY)}\\b)` + + `(?:\\s*(früher|frueher|vorher|davor|zuvor|später|spaeter|danach|nachher|ab\\sjetzt))?`, "i" ); } innerExtract(context: ParsingContext, match: RegExpMatchArray) { - const num = match[2] ? parseNumberPattern(match[2]) : 1; - const unit = TIME_UNIT_DICTIONARY[match[4].toLowerCase()]; - let timeUnits = {}; - timeUnits[unit] = num; - // Modifier - let modifier = match[1] || match[3] || ""; + let modifier = match[1] || match[3] || match[5] || ""; modifier = modifier.toLowerCase(); if (!modifier) { return; } - if (/vor/.test(modifier) || /letzte/.test(modifier) || /vergangen/.test(modifier)) { + let num = match[2] ? parseNumberPattern(match[2]) : 1; + if (/vorvorletzte/.test(modifier) || /überübernächste/.test(modifier)) { + num += 2; + } else if (/vorletzte/.test(modifier) || /übernächste/.test(modifier)) { + num += 1; + } + + const unit = TIME_UNIT_DICTIONARY[match[4].toLowerCase()]; + let timeUnits = {}; + timeUnits[unit] = num; + + if ( + /vor/.test(modifier) || + /letzte/.test(modifier) || + /vergangen/.test(modifier) || + /fr(?:ü|ue)her/.test(modifier) + ) { timeUnits = reverseTimeUnits(timeUnits); } diff --git a/test/de/de_time_units_ago.test.ts b/test/de/de_time_units_ago.test.ts new file mode 100644 index 00000000..276e53f6 --- /dev/null +++ b/test/de/de_time_units_ago.test.ts @@ -0,0 +1,332 @@ +import * as chrono from "../../src/"; +import { testSingleCase, testUnexpectedResult } from "../test_util"; +import { Meridiem } from "../../src/"; + +test("Test - Single Expression", function () { + testSingleCase(chrono.de, "vor 5 Tagen haben wir was gemacht", new Date(2012, 7, 10), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(8); + expect(result.start.get("day")).toBe(5); + + expect(result.index).toBe(0); + expect(result.text).toBe("vor 5 Tagen"); + + expect(result.start).toBeDate(new Date(2012, 8 - 1, 5)); + }); + + testSingleCase(chrono.de, "vor 10 Tagen taten wir was", new Date(2012, 7, 10), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(7); + expect(result.start.get("day")).toBe(31); + + expect(result.index).toBe(0); + expect(result.text).toBe("vor 10 Tagen"); + + expect(result.start).toBeDate(new Date(2012, 7 - 1, 31)); + }); + + testSingleCase(chrono.de, "vor 15 Minuten", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("vor 15 Minuten"); + expect(result.start.get("hour")).toBe(11); + expect(result.start.get("minute")).toBe(59); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 11, 59)); + }); + + testSingleCase(chrono.de, "15 Minuten früher", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("15 Minuten früher"); + expect(result.start.get("hour")).toBe(11); + expect(result.start.get("minute")).toBe(59); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 11, 59)); + }); + + testSingleCase(chrono.de, "15 Minuten zuvor", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("15 Minuten zuvor"); + expect(result.start.get("hour")).toBe(11); + expect(result.start.get("minute")).toBe(59); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 11, 59)); + }); + + testSingleCase(chrono.de, "15 Minuten vorher", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("15 Minuten vorher"); + expect(result.start.get("hour")).toBe(11); + expect(result.start.get("minute")).toBe(59); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 11, 59)); + }); + + testSingleCase(chrono.de, " vor 12 Stunden", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(3); + expect(result.text).toBe("vor 12 Stunden"); + expect(result.start.get("hour")).toBe(0); + expect(result.start.get("minute")).toBe(14); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 0, 14)); + }); + + testSingleCase(chrono.de, "vor 1h", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("vor 1h"); + expect(result.start.get("hour")).toBe(11); + expect(result.start.get("minute")).toBe(14); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + }); + + testSingleCase(chrono.de, "vor 1Std.", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("vor 1Std"); + expect(result.start.get("hour")).toBe(11); + expect(result.start.get("minute")).toBe(14); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + }); + + testSingleCase(chrono.de, " vor einer halben Stunde", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(3); + expect(result.text).toBe("vor einer halben Stunde"); + expect(result.start.get("hour")).toBe(11); + expect(result.start.get("minute")).toBe(44); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 11, 44)); + }); + + testSingleCase(chrono.de, " vor einer viertel Stunde", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(3); + expect(result.text).toBe("vor einer viertel Stunde"); + expect(result.start.get("hour")).toBe(11); + expect(result.start.get("minute")).toBe(59); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 11, 59)); + }); + + testSingleCase(chrono.de, " vor einer dreiviertel Stunde", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(3); + expect(result.text).toBe("vor einer dreiviertel Stunde"); + expect(result.start.get("hour")).toBe(11); + expect(result.start.get("minute")).toBe(29); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 11, 29)); + }); + + testSingleCase(chrono.de, "vor 12 Stunden tat ich was", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("vor 12 Stunden"); + expect(result.start.get("hour")).toBe(0); + expect(result.start.get("minute")).toBe(14); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 0, 14)); + }); + + testSingleCase(chrono.de, "vor 12 Sekunden tat ich was", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("vor 12 Sekunden"); + expect(result.start.get("hour")).toBe(12); + expect(result.start.get("minute")).toBe(13); + expect(result.start.get("second")).toBe(48); + expect(result.start.get("meridiem")).toBe(Meridiem.PM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 12, 13, 48)); + }); + + testSingleCase(chrono.de, "vor drei Sekunden tat ich was", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("vor drei Sekunden"); + expect(result.start.get("hour")).toBe(12); + expect(result.start.get("minute")).toBe(13); + expect(result.start.get("second")).toBe(57); + expect(result.start.get("meridiem")).toBe(Meridiem.PM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 12, 13, 57)); + }); + + testSingleCase(chrono.de, "vor 5 Tagen tag ich was", new Date(2012, 7, 10), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(8); + expect(result.start.get("day")).toBe(5); + + expect(result.index).toBe(0); + expect(result.text).toBe("vor 5 Tagen"); + + expect(result.start).toBeDate(new Date(2012, 8 - 1, 5)); + }); + + testSingleCase(chrono.de, "vor 5 d tat ich was", new Date(2012, 7, 10), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(8); + expect(result.start.get("day")).toBe(5); + + expect(result.index).toBe(0); + expect(result.text).toBe("vor 5 d"); + + expect(result.start).toBeDate(new Date(2012, 8 - 1, 5)); + }); + + testSingleCase(chrono.de, " vor Einer Halben Stunde tat ich...", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(3); + expect(result.text).toBe("vor Einer Halben Stunde"); + expect(result.start.get("hour")).toBe(11); + expect(result.start.get("minute")).toBe(44); + expect(result.start.get("meridiem")).toBe(Meridiem.AM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 11, 44)); + }); + + testSingleCase(chrono.de, "vor einem Tage tat ich was", new Date(2012, 7, 10), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(8); + expect(result.start.get("day")).toBe(9); + + expect(result.index).toBe(0); + expect(result.text).toBe("vor einem Tage"); + + expect(result.start).toBeDate(new Date(2012, 8 - 1, 9)); + }); + + testSingleCase(chrono.de, "vor einer Min.", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("vor einer Min"); + expect(result.start.get("hour")).toBe(12); + expect(result.start.get("minute")).toBe(13); + expect(result.start.get("meridiem")).toBe(Meridiem.PM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 12, 13)); + }); +}); + +test("Test - Single Expression (Casual)", function () { + testSingleCase(chrono.de, "vor 5 Monaten, da sahen wir was", new Date(2012, 10 - 1, 10), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(5); + expect(result.start.get("day")).toBe(10); + + expect(result.index).toBe(0); + expect(result.text).toBe("vor 5 Monaten"); + + expect(result.start).toBeDate(new Date(2012, 5 - 1, 10)); + }); + + testSingleCase(chrono.de, "vor 5 Jahren, da sahen wir was", new Date(2012, 8 - 1, 10), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2007); + expect(result.start.get("month")).toBe(8); + expect(result.start.get("day")).toBe(10); + + expect(result.index).toBe(0); + expect(result.text).toBe("vor 5 Jahren"); + + expect(result.start).toBeDate(new Date(2007, 8 - 1, 10)); + }); + + testSingleCase(chrono.de, "vor einer Woche, da sahen wir was", new Date(2012, 8 - 1, 3), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(7); + expect(result.start.get("day")).toBe(27); + + expect(result.index).toBe(0); + expect(result.text).toBe("vor einer Woche"); + + expect(result.start).toBeDate(new Date(2012, 7 - 1, 27)); + }); + + testSingleCase(chrono.de, "vor zwei Wochen, da sahen wir was", new Date(2012, 8 - 1, 3), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(7); + expect(result.start.get("day")).toBe(20); + + expect(result.index).toBe(0); + expect(result.text).toBe("vor zwei Wochen"); + + expect(result.start).toBeDate(new Date(2012, 7 - 1, 20)); + }); + + testSingleCase(chrono.de, "vorletzte Woche, da sahen wir was", new Date(2012, 8 - 1, 3), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(7); + expect(result.start.get("day")).toBe(20); + + expect(result.index).toBe(0); + expect(result.text).toBe("vorletzte Woche"); + + expect(result.start).toBeDate(new Date(2012, 7 - 1, 20)); + }); + + testSingleCase(chrono.de, "vorvorletzte Woche, da sahen wir was", new Date(2012, 8 - 1, 3), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(7); + expect(result.start.get("day")).toBe(13); + + expect(result.index).toBe(0); + expect(result.text).toBe("vorvorletzte Woche"); + + expect(result.start).toBeDate(new Date(2012, 7 - 1, 13)); + }); + + testSingleCase(chrono.de, "vor ein paar Tagen, da sahen wir was", new Date(2012, 8 - 1, 3), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(8); + expect(result.start.get("day")).toBe(1); + + expect(result.index).toBe(0); + expect(result.text).toBe("vor ein paar Tagen"); + + expect(result.start).toBeDate(new Date(2012, 8 - 1, 1)); + }); +}); + +//test("Test - Nested time ago", function () { +// testSingleCase(chrono.de, "vor 15 Stunden 29 Minuten", new Date(2012, 7, 10, 22, 30), (result) => { +// expect(result.text).toBe("vor 15 Stunden 29 Minuten"); +// expect(result.start.get("day")).toBe(10); +// expect(result.start.get("hour")).toBe(7); +// expect(result.start.get("minute")).toBe(1); +// expect(result.start.get("meridiem")).toBe(Meridiem.AM); +// }); + +// testSingleCase(chrono.de, "vor 1 Tag und 21 Stunden ", new Date(2012, 7, 10, 22, 30), (result) => { +// expect(result.text).toBe("vor 1 Tag und 21 Stunden"); +// expect(result.start.get("day")).toBe(9); +// expect(result.start.get("hour")).toBe(1); +// expect(result.start.get("minute")).toBe(30); +// expect(result.start.get("meridiem")).toBe(Meridiem.AM); +// }); + +// testSingleCase(chrono.de, "vor 3 min 49 sek ", new Date(2012, 7, 10, 22, 30), (result) => { +// expect(result.text).toBe("vor 3 min 49 sek "); +// expect(result.start.get("day")).toBe(10); +// expect(result.start.get("hour")).toBe(22); +// expect(result.start.get("minute")).toBe(26); +// expect(result.start.get("second")).toBe(11); +// expect(result.start.get("meridiem")).toBe(Meridiem.PM); +// }); +//}); + +test("Test - Negative cases", function () { + testUnexpectedResult(chrono.de, "15 Stunden 29 min"); + testUnexpectedResult(chrono.de, "ein paar stunden"); + testUnexpectedResult(chrono.de, "5 Tage"); +}); diff --git a/test/de/de_time_units_later.test.ts b/test/de/de_time_units_later.test.ts new file mode 100644 index 00000000..8c4dd409 --- /dev/null +++ b/test/de/de_time_units_later.test.ts @@ -0,0 +1,151 @@ +import * as chrono from "../../src/"; +import { testSingleCase } from "../test_util"; +import { Meridiem } from "../../src/"; + +test("Test - Later Expression", function () { + testSingleCase(chrono.de, "2 Tage später", new Date(2012, 7, 10, 12), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(8); + expect(result.start.get("day")).toBe(12); + + expect(result.index).toBe(0); + expect(result.text).toBe("2 Tage später"); + + expect(result.start.isCertain("day")).toBe(true); + expect(result.start.isCertain("month")).toBe(true); + + expect(result.start).toBeDate(new Date(2012, 8 - 1, 12, 12)); + }); + + testSingleCase(chrono.de, "5 Minuten später", new Date(2012, 7, 10, 10, 0), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(8); + expect(result.start.get("day")).toBe(10); + expect(result.start.get("hour")).toBe(10); + expect(result.start.get("minute")).toBe(5); + + expect(result.index).toBe(0); + expect(result.text).toBe("5 Minuten später"); + + expect(result.start.isCertain("hour")).toBe(true); + expect(result.start.isCertain("minute")).toBe(true); + + expect(result.start).toBeDate(new Date(2012, 8 - 1, 10, 10, 5)); + }); + + testSingleCase(chrono.de, "3 Wochen später", new Date(2012, 7 - 1, 10, 10, 0), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(7); + expect(result.start.get("day")).toBe(31); + + expect(result.index).toBe(0); + expect(result.text).toBe("3 Wochen später"); + + expect(result.start).toBeDate(new Date(2012, 7 - 1, 31, 10, 0)); + }); +}); + +test("Test - From now Expression", () => { + testSingleCase(chrono.de, "in 5 Tagen, werden wir was tun", new Date(2012, 7, 10), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(8); + expect(result.start.get("day")).toBe(15); + + expect(result.index).toBe(0); + expect(result.text).toBe("in 5 Tagen"); + + expect(result.start).toBeDate(new Date(2012, 8 - 1, 15)); + }); + + testSingleCase(chrono.de, "in 10 Tagen, we did something", new Date(2012, 7, 10), (result) => { + expect(result.start).not.toBeNull(); + expect(result.start.get("year")).toBe(2012); + expect(result.start.get("month")).toBe(8); + expect(result.start.get("day")).toBe(20); + + expect(result.index).toBe(0); + expect(result.text).toBe("in 10 Tagen"); + + expect(result.start).toBeDate(new Date(2012, 8 - 1, 20)); + }); + + testSingleCase(chrono.de, "in 15 Minuten", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("in 15 Minuten"); + expect(result.start.get("hour")).toBe(12); + expect(result.start.get("minute")).toBe(29); + expect(result.start.get("meridiem")).toBe(Meridiem.PM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 12, 29)); + }); + + testSingleCase(chrono.de, "nach 15 Minuten", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("nach 15 Minuten"); + expect(result.start.get("hour")).toBe(12); + expect(result.start.get("minute")).toBe(29); + expect(result.start.get("meridiem")).toBe(Meridiem.PM); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 12, 29)); + }); + + testSingleCase(chrono.de, "ab jetzt in drei Sekunden geht es los", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("ab jetzt in drei Sekunden"); + expect(result.start.get("hour")).toBe(12); + expect(result.start.get("minute")).toBe(14); + expect(result.start.get("second")).toBe(3); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 12, 14, 3)); + }); + + testSingleCase(chrono.de, "eine Minute ab jetzt", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("eine Minute ab jetzt"); + expect(result.start.get("hour")).toBe(12); + expect(result.start.get("minute")).toBe(15); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 12, 15)); + }); + + testSingleCase(chrono.de, "in 1 Stunde", new Date(2012, 7, 10, 12, 14), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("in 1 Stunde"); + expect(result.start.get("hour")).toBe(13); + expect(result.start.get("minute")).toBe(14); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 13, 14)); + }); + + testSingleCase(chrono.de, "in 1,5 Stunden", new Date(2012, 7, 10, 12, 40), (result) => { + expect(result.index).toBe(0); + expect(result.text).toBe("in 1,5 Stunden"); + expect(result.start.get("hour")).toBe(14); + expect(result.start.get("minute")).toBe(10); + + expect(result.start).toBeDate(new Date(2012, 7, 10, 14, 10)); + }); +}); + +// test("Test - Strict mode", function () { +// testSingleCase(chrono.de.strict, "15 Minuten ab jetzt", new Date(2012, 7, 10, 12, 14), (result, text) => { +// expect(result.text).toBe(text); +// expect(result.start.get("hour")).toBe(12); +// expect(result.start.get("minute")).toBe(29); +// +// expect(result.start).toBeDate(new Date(2012, 7, 10, 12, 29)); +// }); +// +// testSingleCase(chrono.de.strict, "25 Minuten später", new Date(2012, 7, 10, 12, 40), (result) => { +// expect(result.index).toBe(0); +// expect(result.text).toBe("25 Minuten später"); +// expect(result.start.get("hour")).toBe(13); +// expect(result.start.get("minute")).toBe(5); +// +// expect(result.start).toBeDate(new Date(2012, 7, 10, 13, 5)); +// }); +// });