diff --git a/src/locales/de/constants.ts b/src/locales/de/constants.ts index ec695d0b..2876d860 100644 --- a/src/locales/de/constants.ts +++ b/src/locales/de/constants.ts @@ -71,6 +71,7 @@ export const INTEGER_WORD_DICTIONARY: { [word: string]: number } = { "einem": 1, "einen": 1, "einer": 1, + "eines": 1, "zwei": 2, "drei": 3, "vier": 4, @@ -86,6 +87,162 @@ export const INTEGER_WORD_DICTIONARY: { [word: string]: number } = { "zwoelf": 12, }; +/** German ordinal day words (1–31), from https://github.com/wanasit/chrono/pull/442 */ +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, + vierter: 4, + viertes: 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, + achtundzwanzigste: 28, + achtundzwanzigsten: 28, + achtundzwanzigster: 28, + achtundzwanzigstes: 28, + neunundzwanzigste: 29, + neunundzwanzigsten: 29, + neunundzwanzigster: 29, + neunundzwanzigstes: 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]: Timeunit } = { sek: "second", sekunde: "second", @@ -95,8 +252,11 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: Timeunit } = { minuten: "minute", h: "hour", std: "hour", + "std.": "hour", stunde: "hour", stunden: "hour", + d: "day", + tg: "day", tag: "day", tage: "day", tagen: "day", @@ -123,25 +283,49 @@ export const TIME_UNIT_DICTIONARY: { [word: string]: Timeunit } = { export const NUMBER_PATTERN = `(?:${matchAnyPattern( INTEGER_WORD_DICTIONARY -)}|[0-9]+|[0-9]+\\.[0-9]+|halb?|halbe?|einigen?|wenigen?|mehreren?)`; +)}|[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 === "ein" || num === "einer" || num === "einem" || num === "einen" || num === "eine") { + } else if ( + num === "ein" || + num === "einer" || + num === "einem" || + num === "einen" || + num === "eine" || + num === "eines" + ) { return 1; - } else if (num.match(/wenigen/)) { - return 2; - } else if (num.match(/halb/) || num.match(/halben/)) { + } else if (num.match(/wenige/)) { + return 3; + } else if (num.match(/halb/)) { return 0.5; - } else if (num.match(/einigen/)) { + } 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(/einige/)) { return 3; - } else if (num.match(/mehreren/)) { + } else if (num.match(/mehrere/)) { return 7; } - return parseFloat(num); + return parseFloat(num.replace(",", ".")); +} + +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); } //----------------------------- 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/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts b/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts index 35a3a1e7..4f676a75 100644 --- a/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts +++ b/src/locales/de/parsers/DETimeUnitRelativeFormatParser.ts @@ -3,37 +3,55 @@ import { NUMBER_PATTERN, parseNumberPattern, TIME_UNIT_DICTIONARY } from "../con import { ParsingComponents } from "../../../results"; import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary"; import { matchAnyPattern } from "../../../utils/pattern"; -import { reverseDuration } from "../../../calculation/duration"; - -export default class DETimeUnitAgoFormatParser extends AbstractParserWithWordBoundaryChecking { - constructor() { - super(); - } +import { Duration, reverseDuration } from "../../../calculation/duration"; +/** + * Relative DE time units, e.g.: + * - "vor 3 Tagen", "in 2 Wochen" + * - "letzte Woche", "vorletzte Woche", "übernächste Woche" + * - "15 Minuten früher", "10 Minuten später" + * + * Revives and updates https://github.com/wanasit/chrono/pull/442 on current APIs + * (reverseDuration instead of reverseTimeUnits). + */ +export default class DETimeUnitRelativeFormatParser extends AbstractParserWithWordBoundaryChecking { 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übernächste|übernächste|nächste|kommende|folgende|vorvorletzte|vorletzte|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)})(?=\\W|$)`, + `\\s*(${matchAnyPattern(TIME_UNIT_DICTIONARY)})` + + `(?:\\s*(früher|frueher|vorher|davor|zuvor|später|spaeter|danach|nachher|ab\\sjetzt))?` + + `(?=\\W|$)`, "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: Duration = {}; + timeUnits[unit] = num; + + if ( + /vor/.test(modifier) || + /letzte/.test(modifier) || + /vergangen/.test(modifier) || + /fr(?:ü|ue)her/.test(modifier) || + /davor|zuvor|vorher/.test(modifier) + ) { timeUnits = reverseDuration(timeUnits); } diff --git a/test/de/de_month_name_little_endian.test.ts b/test/de/de_month_name_little_endian.test.ts index 33a4d561..beb985e0 100644 --- a/test/de/de_month_name_little_endian.test.ts +++ b/test/de/de_month_name_little_endian.test.ts @@ -271,3 +271,16 @@ test("Test - Combined expression", function () { test("Test - Impossible Dates (Casual Mode)", function () { testUnexpectedResult(chrono.de, "32. Oktober 2015"); }); + +test("Test - Ordinal day names", function () { + testSingleCase(chrono.de, "am dritten Oktober", new Date(2012, 7, 10), (result) => { + expect(result.text).toBe("am dritten Oktober"); + expect(result.start.get("day")).toBe(3); + expect(result.start.get("month")).toBe(10); + }); + + testSingleCase(chrono.de, "zehnter jänner 2012", new Date(2012, 7, 10), (result) => { + expect(result.text).toBe("zehnter jänner 2012"); + expect(result.start).toBeDate(new Date(2012, 1 - 1, 10, 12)); + }); +}); 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..aca05b5f --- /dev/null +++ b/test/de/de_time_units_ago.test.ts @@ -0,0 +1,305 @@ +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 - 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..fb459895 --- /dev/null +++ b/test/de/de_time_units_later.test.ts @@ -0,0 +1,132 @@ +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)); + }); +});