timelang 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -284,9 +284,7 @@ var lexer = import_moo.default.compile({
284
284
  // EOD/COB keywords
285
285
  kw_eod: ["eod"],
286
286
  kw_cob: ["cob"],
287
- kw_close: ["close"],
288
- // Week keyword (for "week 1" patterns)
289
- kw_week: ["week"]
287
+ kw_close: ["close"]
290
288
  })
291
289
  // Keywords are matched against lowercase input
292
290
  },
@@ -694,6 +692,20 @@ var grammar = {
694
692
  { "name": "relativeDate", "symbols": ["dayUnit", "_", "afterConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("future", makeDuration(1, "day"), d[4]) },
695
693
  { "name": "relativeDate", "symbols": ["wordNumber", "_", "unit", "_", "beforeConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("past", makeDuration(parseWordNumber(d[0]), d[2]), d[6]) },
696
694
  { "name": "relativeDate", "symbols": ["wordNumber", "_", "unit", "_", "afterConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("future", makeDuration(parseWordNumber(d[0]), d[2]), d[6]) },
695
+ { "name": "relativeDate", "symbols": ["nextRelative", "_", "businessKeyword", "_", "dayOrDaysUnit"], "postprocess": (d) => makeRelativeDate("future", makeDuration(1, "businessDay")) },
696
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "number", "_", "businessKeyword", "_", "dayOrDaysUnit"], "postprocess": (d) => makeRelativeDate("future", makeDuration(d[2], "businessDay")) },
697
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "wordNumber", "_", "businessKeyword", "_", "dayOrDaysUnit"], "postprocess": (d) => makeRelativeDate("future", makeDuration(parseWordNumber(d[2]), "businessDay")) },
698
+ { "name": "relativeDate", "symbols": ["number", "_", "businessKeyword", "_", "dayOrDaysUnit", "_", "agoConnector"], "postprocess": (d) => makeRelativeDate("past", makeDuration(d[0], "businessDay")) },
699
+ { "name": "relativeDate", "symbols": ["wordNumber", "_", "businessKeyword", "_", "dayOrDaysUnit", "_", "agoConnector"], "postprocess": (d) => makeRelativeDate("past", makeDuration(parseWordNumber(d[0]), "businessDay")) },
700
+ { "name": "relativeDate", "symbols": ["wordNumber", "_", "fortnightKeyword", "_", "fromConnector", "_", "now"], "postprocess": (d) => makeRelativeDate("future", makeDuration(parseWordNumber(d[0]) * 2, "week")) },
701
+ { "name": "relativeDate", "symbols": ["number", "_", "fortnightKeyword", "_", "fromConnector", "_", "now"], "postprocess": (d) => makeRelativeDate("future", makeDuration(d[0] * 2, "week")) },
702
+ { "name": "relativeDate", "symbols": ["fortnightKeyword", "_", "fromConnector", "_", "now"], "postprocess": (d) => makeRelativeDate("future", makeDuration(2, "week")) },
703
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "wordNumber", "_", "fortnightKeyword"], "postprocess": (d) => makeRelativeDate("future", makeDuration(parseWordNumber(d[2]) * 2, "week")) },
704
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "number", "_", "fortnightKeyword"], "postprocess": (d) => makeRelativeDate("future", makeDuration(d[2] * 2, "week")) },
705
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "fortnightKeyword"], "postprocess": (d) => makeRelativeDate("future", makeDuration(2, "week")) },
706
+ { "name": "relativeDate", "symbols": ["wordNumber", "_", "fortnightKeyword", "_", "agoConnector"], "postprocess": (d) => makeRelativeDate("past", makeDuration(parseWordNumber(d[0]) * 2, "week")) },
707
+ { "name": "relativeDate", "symbols": ["number", "_", "fortnightKeyword", "_", "agoConnector"], "postprocess": (d) => makeRelativeDate("past", makeDuration(d[0] * 2, "week")) },
708
+ { "name": "relativeDate", "symbols": ["fortnightKeyword", "_", "agoConnector"], "postprocess": (d) => makeRelativeDate("past", makeDuration(2, "week")) },
697
709
  { "name": "fuzzy", "symbols": ["quarter"], "postprocess": (d) => makeFuzzy({ period: "quarter", quarter: parseQuarter(d[0].value) }) },
698
710
  { "name": "fuzzy", "symbols": ["quarter", "_", "year"], "postprocess": (d) => makeFuzzy({ period: "quarter", quarter: parseQuarter(d[0].value), year: d[2] }) },
699
711
  { "name": "fuzzy", "symbols": ["half"], "postprocess": (d) => makeFuzzy({ period: "half", half: parseHalf(d[0].value) }) },
@@ -794,11 +806,13 @@ var grammar = {
794
806
  { "name": "fuzzy", "symbols": ["lastRelative", "_", "nightKeyword"], "postprocess": (d) => makeFuzzy({ period: "night", relative: "last" }) },
795
807
  { "name": "fuzzy", "symbols": ["tomorrow", "_", "nightKeyword"], "postprocess": (d) => makeFuzzy({ period: "night", relative: "tomorrow" }) },
796
808
  { "name": "fuzzy", "symbols": ["weekday", "_", "nightKeyword"], "postprocess": (d) => makeFuzzy({ period: "night", weekday: d[0] }) },
797
- { "name": "fuzzy", "symbols": ["fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight" }) },
798
- { "name": "fuzzy", "symbols": ["nextRelative", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", relative: "next" }) },
799
- { "name": "fuzzy", "symbols": ["lastRelative", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", relative: "last" }) },
800
- { "name": "fuzzy", "symbols": ["inConnector", "_", "wordNumber", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", count: parseWordNumber(d[2]) }) },
801
- { "name": "fuzzy", "symbols": ["inConnector", "_", "number", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", count: d[2] }) },
809
+ { "name": "fuzzy", "symbols": ["laterKeyword", "_", "today"], "postprocess": (d) => makeFuzzy({ period: "day", modifier: "later" }) },
810
+ { "name": "fuzzy", "symbols": ["earlierKeyword", "_", "today"], "postprocess": (d) => makeFuzzy({ period: "day", modifier: "earlier" }) },
811
+ { "name": "fuzzy", "symbols": ["laterKeyword", "_", "thisRelative", "_", "unit"], "postprocess": (d) => makeFuzzy({ period: d[4], modifier: "later", relative: "this" }) },
812
+ { "name": "fuzzy", "symbols": ["earlierKeyword", "_", "thisRelative", "_", "unit"], "postprocess": (d) => makeFuzzy({ period: d[4], modifier: "earlier", relative: "this" }) },
813
+ { "name": "fuzzy", "symbols": ["weekKeyword", "_", "number"], "postprocess": (d) => makeFuzzy({ period: "weekNumber", weekNumber: d[2] }) },
814
+ { "name": "fuzzy", "symbols": ["weekKeyword", "_", "number", "_", "year"], "postprocess": (d) => makeFuzzy({ period: "weekNumber", weekNumber: d[2], year: d[4] }) },
815
+ { "name": "fuzzy", "symbols": ["theConnector", "_", "weekKeyword", "_", "ofConnector", "_", "date"], "postprocess": (d) => makeFuzzy({ period: "weekOf", baseDate: d[6] }) },
802
816
  { "name": "duration", "symbols": ["number", "_", "unit"], "postprocess": (d) => makeDuration(d[0], d[2]) },
803
817
  { "name": "duration", "symbols": ["wordNumber", "_", "unit"], "postprocess": (d) => makeDuration(parseWordNumber(d[0]), d[2]) },
804
818
  { "name": "duration", "symbols": ["abbreviatedDuration"], "postprocess": (d) => d[0] },
@@ -842,6 +856,7 @@ var grammar = {
842
856
  { "name": "date", "symbols": ["yearOnly"], "postprocess": first },
843
857
  { "name": "date", "symbols": ["timeOnly"], "postprocess": first },
844
858
  { "name": "date", "symbols": ["dayOnly"], "postprocess": first },
859
+ { "name": "date", "symbols": ["eodCobDate"], "postprocess": first },
845
860
  { "name": "monthDayCompact", "symbols": [lexer.has("monthDayCompact") ? { type: "monthDayCompact" } : monthDayCompact], "postprocess": (d) => {
846
861
  const parsed = parseMonthDayCompact(d[0].value);
847
862
  return makeDate({ month: parsed.month, day: parsed.day });
@@ -860,6 +875,15 @@ var grammar = {
860
875
  { "name": "timeOnly", "symbols": ["timeWord"], "postprocess": (d) => makeDate({ time: { special: d[0] }, timeOnly: true }) },
861
876
  { "name": "dayOnly", "symbols": ["theConnector", "_", "dayNumber"], "postprocess": (d) => makeDate({ day: d[2], dayOnly: true }) },
862
877
  { "name": "dayOnly", "symbols": ["onConnector", "_", "theConnector", "_", "dayNumber"], "postprocess": (d) => makeDate({ day: d[4], dayOnly: true }) },
878
+ { "name": "eodCobDate", "symbols": ["eodKeyword"], "postprocess": (d) => makeDate({ special: "today", time: { hour: 23, minute: 59 } }) },
879
+ { "name": "eodCobDate", "symbols": ["cobKeyword"], "postprocess": (d) => makeDate({ special: "today", time: { hour: 17, minute: 0 } }) },
880
+ { "name": "eodCobDate", "symbols": ["eodKeyword", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], time: { hour: 23, minute: 59 } }) },
881
+ { "name": "eodCobDate", "symbols": ["cobKeyword", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], time: { hour: 17, minute: 0 } }) },
882
+ { "name": "eodCobDate", "symbols": ["eodKeyword", "_", "specialDay"], "postprocess": (d) => makeDate({ special: d[2], time: { hour: 23, minute: 59 } }) },
883
+ { "name": "eodCobDate", "symbols": ["cobKeyword", "_", "specialDay"], "postprocess": (d) => makeDate({ special: d[2], time: { hour: 17, minute: 0 } }) },
884
+ { "name": "eodCobDate", "symbols": ["endConnector", "_", "ofConnector", "_", "dayUnit", "_", "specialDay"], "postprocess": (d) => makeDate({ special: d[6], time: { hour: 23, minute: 59 } }) },
885
+ { "name": "eodCobDate", "symbols": ["closeKeyword", "_", "ofConnector", "_", "businessKeyword", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[6], time: { hour: 17, minute: 0 } }) },
886
+ { "name": "eodCobDate", "symbols": ["closeKeyword", "_", "ofConnector", "_", "businessKeyword", "_", "specialDay"], "postprocess": (d) => makeDate({ special: d[6], time: { hour: 17, minute: 0 } }) },
863
887
  { "name": "specialDay", "symbols": ["today"], "postprocess": (d) => "today" },
864
888
  { "name": "specialDay", "symbols": ["tomorrow"], "postprocess": (d) => "tomorrow" },
865
889
  { "name": "specialDay", "symbols": ["yesterday"], "postprocess": (d) => "yesterday" },
@@ -869,6 +893,7 @@ var grammar = {
869
893
  { "name": "specialDay", "symbols": ["theConnector", "_", "dayUnit", "_", "beforeConnector", "_", "yesterday"], "postprocess": (d) => "dayBeforeYesterday" },
870
894
  { "name": "specialDay", "symbols": ["dayUnit", "_", "beforeConnector", "_", "yesterday"], "postprocess": (d) => "dayBeforeYesterday" },
871
895
  { "name": "dayUnit", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d, _, reject) => d[0].value === "day" ? d[0] : reject },
896
+ { "name": "dayOrDaysUnit", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d, _, reject) => d[0].value === "day" || d[0].value === "days" ? d[0] : reject },
872
897
  { "name": "relativeWeekday", "symbols": ["nextRelative", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], relative: "next" }) },
873
898
  { "name": "relativeWeekday", "symbols": ["lastRelative", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], relative: "last" }) },
874
899
  { "name": "relativeWeekday", "symbols": ["thisRelative", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], relative: "this" }) },
@@ -912,6 +937,9 @@ var grammar = {
912
937
  { "name": "dateWithTime", "symbols": ["time", "_", "date"], "postprocess": (d) => ({ ...d[2], time: d[0] }) },
913
938
  { "name": "dateWithTime", "symbols": ["timeWord", "_", "date"], "postprocess": (d) => ({ ...d[2], time: { special: d[0] } }) },
914
939
  { "name": "dateWithTime", "symbols": ["date", "_", "time"], "postprocess": (d) => ({ ...d[0], time: d[2] }) },
940
+ { "name": "dateWithTime", "symbols": ["timeWord", "_", "onConnector", "_", "date"], "postprocess": (d) => ({ ...d[4], time: { special: d[0] } }) },
941
+ { "name": "dateWithTime", "symbols": ["timeWord", "_", "onConnector", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[4], time: { special: d[0] } }) },
942
+ { "name": "dateWithTime", "symbols": ["midnight", "_", "tonightKeyword"], "postprocess": (d) => makeDate({ special: "tonight", time: { special: "midnight" } }) },
915
943
  { "name": "complexDate", "symbols": ["nextRelative", "_", "unit", "_", "weekday", "_", "time"], "postprocess": (d) => makeDate({ relative: "next", period: d[2], weekday: d[4], time: d[6] }) },
916
944
  { "name": "complexDate", "symbols": ["nextRelative", "_", "unit", "_", "weekday"], "postprocess": (d) => makeDate({ relative: "next", period: d[2], weekday: d[4] }) },
917
945
  { "name": "complexDate", "symbols": ["lastRelative", "_", "unit", "_", "weekday", "_", "time"], "postprocess": (d) => makeDate({ relative: "last", period: d[2], weekday: d[4], time: d[6] }) },
@@ -948,6 +976,45 @@ var grammar = {
948
976
  if (d[1].value === "am" && hour === 12) hour = 0;
949
977
  return { hour, minute: 0 };
950
978
  } },
979
+ { "name": "time", "symbols": ["quarterKeyword", "_", "pastConnector", "_", "hourNumber"], "postprocess": (d) => ({ hour: d[4], minute: 15 }) },
980
+ { "name": "time", "symbols": ["quarterKeyword", "_", "pastConnector", "_", "hourNumber", lexer.has("ampm") ? { type: "ampm" } : ampm], "postprocess": (d) => {
981
+ let hour = d[4];
982
+ if (d[5].value === "pm" && hour !== 12) hour += 12;
983
+ if (d[5].value === "am" && hour === 12) hour = 0;
984
+ return { hour, minute: 15 };
985
+ } },
986
+ { "name": "time", "symbols": ["halfWord", "_", "pastConnector", "_", "hourNumber"], "postprocess": (d) => ({ hour: d[4], minute: 30 }) },
987
+ { "name": "time", "symbols": ["halfWord", "_", "pastConnector", "_", "hourNumber", lexer.has("ampm") ? { type: "ampm" } : ampm], "postprocess": (d) => {
988
+ let hour = d[4];
989
+ if (d[5].value === "pm" && hour !== 12) hour += 12;
990
+ if (d[5].value === "am" && hour === 12) hour = 0;
991
+ return { hour, minute: 30 };
992
+ } },
993
+ { "name": "time", "symbols": ["quarterKeyword", "_", "toConnector", "_", "hourNumber"], "postprocess": (d) => ({ hour: d[4] - 1, minute: 45 }) },
994
+ { "name": "time", "symbols": ["quarterKeyword", "_", "toConnector", "_", "hourNumber", lexer.has("ampm") ? { type: "ampm" } : ampm], "postprocess": (d) => {
995
+ let hour = d[4];
996
+ if (d[5].value === "pm" && hour !== 12) hour += 12;
997
+ if (d[5].value === "am" && hour === 12) hour = 0;
998
+ return { hour: hour - 1, minute: 45 };
999
+ } },
1000
+ { "name": "time", "symbols": ["number", "_", "pastConnector", "_", "hourNumber"], "postprocess": (d) => ({ hour: d[4], minute: d[0] }) },
1001
+ { "name": "time", "symbols": ["number", "_", "pastConnector", "_", "hourNumber", lexer.has("ampm") ? { type: "ampm" } : ampm], "postprocess": (d) => {
1002
+ let hour = d[4];
1003
+ if (d[5].value === "pm" && hour !== 12) hour += 12;
1004
+ if (d[5].value === "am" && hour === 12) hour = 0;
1005
+ return { hour, minute: d[0] };
1006
+ } },
1007
+ { "name": "time", "symbols": ["number", "_", "toConnector", "_", "hourNumber"], "postprocess": (d) => ({ hour: d[4] - 1, minute: 60 - d[0] }) },
1008
+ { "name": "time", "symbols": ["number", "_", "toConnector", "_", "hourNumber", lexer.has("ampm") ? { type: "ampm" } : ampm], "postprocess": (d) => {
1009
+ let hour = d[4];
1010
+ if (d[5].value === "pm" && hour !== 12) hour += 12;
1011
+ if (d[5].value === "am" && hour === 12) hour = 0;
1012
+ return { hour: hour - 1, minute: 60 - d[0] };
1013
+ } },
1014
+ { "name": "time", "symbols": ["number", "_", "toConnector", "_", "noon"], "postprocess": (d) => ({ hour: 11, minute: 60 - d[0] }) },
1015
+ { "name": "time", "symbols": ["number", "_", "toConnector", "_", "midnight"], "postprocess": (d) => ({ hour: 23, minute: 60 - d[0] }) },
1016
+ { "name": "time", "symbols": ["quarterKeyword", "_", "toConnector", "_", "noon"], "postprocess": (d) => ({ hour: 11, minute: 45 }) },
1017
+ { "name": "time", "symbols": ["quarterKeyword", "_", "toConnector", "_", "midnight"], "postprocess": (d) => ({ hour: 23, minute: 45 }) },
951
1018
  { "name": "timeWord", "symbols": ["noon"], "postprocess": (d) => "noon" },
952
1019
  { "name": "timeWord", "symbols": ["midnight"], "postprocess": (d) => "midnight" },
953
1020
  { "name": "number", "symbols": [lexer.has("integer") ? { type: "integer" } : integer], "postprocess": (d) => parseInt(d[0].value, 10) },
@@ -1044,10 +1111,28 @@ var grammar = {
1044
1111
  { "name": "now", "symbols": [lexer.has("kw_now") ? { type: "kw_now" } : kw_now], "postprocess": first },
1045
1112
  { "name": "noon", "symbols": [lexer.has("kw_noon") ? { type: "kw_noon" } : kw_noon], "postprocess": first },
1046
1113
  { "name": "midnight", "symbols": [lexer.has("kw_midnight") ? { type: "kw_midnight" } : kw_midnight], "postprocess": first },
1114
+ { "name": "quarterKeyword", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d, _, reject) => d[0].value === "quarter" ? d[0] : reject },
1115
+ { "name": "hourNumber", "symbols": [lexer.has("integer") ? { type: "integer" } : integer], "postprocess": (d, _, reject) => {
1116
+ const val = parseInt(d[0].value, 10);
1117
+ if (val < 1 || val > 12) return reject;
1118
+ return val;
1119
+ } },
1120
+ { "name": "pastConnector", "symbols": [lexer.has("kw_past") ? { type: "kw_past" } : kw_past], "postprocess": first },
1047
1121
  { "name": "weekendKeyword", "symbols": [lexer.has("kw_weekend") ? { type: "kw_weekend" } : kw_weekend], "postprocess": first },
1048
1122
  { "name": "tonightKeyword", "symbols": [lexer.has("kw_tonight") ? { type: "kw_tonight" } : kw_tonight], "postprocess": first },
1049
1123
  { "name": "nightKeyword", "symbols": [lexer.has("kw_night") ? { type: "kw_night" } : kw_night], "postprocess": first },
1050
1124
  { "name": "fortnightKeyword", "symbols": [lexer.has("kw_fortnight") ? { type: "kw_fortnight" } : kw_fortnight], "postprocess": first },
1125
+ { "name": "laterKeyword", "symbols": [lexer.has("otherKeyword") ? { type: "otherKeyword" } : otherKeyword], "postprocess": (d, _, reject) => d[0].value === "later" ? d[0] : reject },
1126
+ { "name": "earlierKeyword", "symbols": [lexer.has("otherKeyword") ? { type: "otherKeyword" } : otherKeyword], "postprocess": (d, _, reject) => d[0].value === "earlier" ? d[0] : reject },
1127
+ { "name": "weekKeyword", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d, _, reject) => {
1128
+ const val = d[0].value.toLowerCase();
1129
+ if (val === "week" || val === "weeks") return d[0];
1130
+ return reject;
1131
+ } },
1132
+ { "name": "businessKeyword", "symbols": [lexer.has("kw_business") ? { type: "kw_business" } : kw_business], "postprocess": first },
1133
+ { "name": "eodKeyword", "symbols": [lexer.has("kw_eod") ? { type: "kw_eod" } : kw_eod], "postprocess": first },
1134
+ { "name": "cobKeyword", "symbols": [lexer.has("kw_cob") ? { type: "kw_cob" } : kw_cob], "postprocess": first },
1135
+ { "name": "closeKeyword", "symbols": [lexer.has("kw_close") ? { type: "kw_close" } : kw_close], "postprocess": first },
1051
1136
  { "name": "_$ebnf$1", "symbols": [] },
1052
1137
  { "name": "_$ebnf$1", "symbols": ["_$ebnf$1", lexer.has("ws") ? { type: "ws" } : ws], "postprocess": (d) => d[0].concat([d[1]]) },
1053
1138
  { "name": "_", "symbols": ["_$ebnf$1"], "postprocess": nuller }
@@ -1793,6 +1878,42 @@ function getBasePeriodDates(node, opts, year) {
1793
1878
  const end = new Date(start.getTime() + 6 * MS_PER_DAY);
1794
1879
  return { start, end };
1795
1880
  }
1881
+ if (node.period === "weekNumber" && node.weekNumber !== void 0) {
1882
+ const weekNum = node.weekNumber;
1883
+ const targetYear = node.year ?? ref.getUTCFullYear();
1884
+ const weekStart = opts.weekStartsOn === "monday" ? 1 : 0;
1885
+ const jan1 = new Date(Date.UTC(targetYear, 0, 1));
1886
+ const jan1Day = jan1.getUTCDay();
1887
+ const daysToFirstWeekStart = (weekStart - jan1Day + 7) % 7;
1888
+ const firstWeekStart = new Date(jan1.getTime() + daysToFirstWeekStart * MS_PER_DAY);
1889
+ const start = new Date(firstWeekStart.getTime() + (weekNum - 1) * MS_PER_WEEK);
1890
+ const end = new Date(start.getTime() + 6 * MS_PER_DAY);
1891
+ return { start, end };
1892
+ }
1893
+ if (node.period === "weekOf" && node.baseDate) {
1894
+ const baseDate = node.baseDate;
1895
+ let targetDate;
1896
+ if (baseDate.month !== void 0 && baseDate.day !== void 0) {
1897
+ const month2 = typeof baseDate.month === "number" ? baseDate.month - 1 : 0;
1898
+ const day = baseDate.day;
1899
+ const targetYear = baseDate.year ?? ref.getUTCFullYear();
1900
+ targetDate = new Date(Date.UTC(targetYear, month2, day));
1901
+ } else {
1902
+ targetDate = ref;
1903
+ }
1904
+ const weekStart = opts.weekStartsOn === "monday" ? 1 : 0;
1905
+ const currentDay = targetDate.getUTCDay();
1906
+ const daysFromStart = (currentDay - weekStart + 7) % 7;
1907
+ const start = new Date(
1908
+ Date.UTC(
1909
+ targetDate.getUTCFullYear(),
1910
+ targetDate.getUTCMonth(),
1911
+ targetDate.getUTCDate() - daysFromStart
1912
+ )
1913
+ );
1914
+ const end = new Date(start.getTime() + 6 * MS_PER_DAY);
1915
+ return { start, end };
1916
+ }
1796
1917
  if (node.period === "day") {
1797
1918
  const start = new Date(
1798
1919
  Date.UTC(ref.getUTCFullYear(), ref.getUTCMonth(), ref.getUTCDate())
@@ -1956,7 +2077,7 @@ function convertASTToResult(ast, opts, originalInput) {
1956
2077
  const periodDates = convertFuzzyNodeWithoutModifier(expression, opts);
1957
2078
  return { type: "date", date: periodDates.end, title };
1958
2079
  }
1959
- if (period === "weekend" || period === "night" || period === "tonight" || period === "fortnight") {
2080
+ if (period === "weekend" || period === "night" || period === "tonight" || period === "fortnight" || period === "weekNumber" || period === "weekOf") {
1960
2081
  const duration = end.getTime() - start.getTime();
1961
2082
  return { type: "span", start, end, duration, title };
1962
2083
  }
@@ -2010,6 +2131,16 @@ function convertASTToResult(ast, opts, originalInput) {
2010
2131
  baseDate.getUTCMinutes()
2011
2132
  )
2012
2133
  );
2134
+ } else if (durationUnit === "businessDay" || durationUnit === "businessday") {
2135
+ resultDate = new Date(Date.UTC(baseDate.getUTCFullYear(), baseDate.getUTCMonth(), baseDate.getUTCDate()));
2136
+ let daysToAdd = durationValue;
2137
+ while (daysToAdd > 0) {
2138
+ resultDate.setUTCDate(resultDate.getUTCDate() + direction);
2139
+ const dayOfWeek = resultDate.getUTCDay();
2140
+ if (dayOfWeek !== 0 && dayOfWeek !== 6) {
2141
+ daysToAdd--;
2142
+ }
2143
+ }
2013
2144
  } else {
2014
2145
  const durationMs = convertDurationNode(durationNode);
2015
2146
  resultDate = new Date(baseDate.getTime() + direction * durationMs);