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.js CHANGED
@@ -244,9 +244,7 @@ var lexer = moo.compile({
244
244
  // EOD/COB keywords
245
245
  kw_eod: ["eod"],
246
246
  kw_cob: ["cob"],
247
- kw_close: ["close"],
248
- // Week keyword (for "week 1" patterns)
249
- kw_week: ["week"]
247
+ kw_close: ["close"]
250
248
  })
251
249
  // Keywords are matched against lowercase input
252
250
  },
@@ -654,6 +652,20 @@ var grammar = {
654
652
  { "name": "relativeDate", "symbols": ["dayUnit", "_", "afterConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("future", makeDuration(1, "day"), d[4]) },
655
653
  { "name": "relativeDate", "symbols": ["wordNumber", "_", "unit", "_", "beforeConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("past", makeDuration(parseWordNumber(d[0]), d[2]), d[6]) },
656
654
  { "name": "relativeDate", "symbols": ["wordNumber", "_", "unit", "_", "afterConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("future", makeDuration(parseWordNumber(d[0]), d[2]), d[6]) },
655
+ { "name": "relativeDate", "symbols": ["nextRelative", "_", "businessKeyword", "_", "dayOrDaysUnit"], "postprocess": (d) => makeRelativeDate("future", makeDuration(1, "businessDay")) },
656
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "number", "_", "businessKeyword", "_", "dayOrDaysUnit"], "postprocess": (d) => makeRelativeDate("future", makeDuration(d[2], "businessDay")) },
657
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "wordNumber", "_", "businessKeyword", "_", "dayOrDaysUnit"], "postprocess": (d) => makeRelativeDate("future", makeDuration(parseWordNumber(d[2]), "businessDay")) },
658
+ { "name": "relativeDate", "symbols": ["number", "_", "businessKeyword", "_", "dayOrDaysUnit", "_", "agoConnector"], "postprocess": (d) => makeRelativeDate("past", makeDuration(d[0], "businessDay")) },
659
+ { "name": "relativeDate", "symbols": ["wordNumber", "_", "businessKeyword", "_", "dayOrDaysUnit", "_", "agoConnector"], "postprocess": (d) => makeRelativeDate("past", makeDuration(parseWordNumber(d[0]), "businessDay")) },
660
+ { "name": "relativeDate", "symbols": ["wordNumber", "_", "fortnightKeyword", "_", "fromConnector", "_", "now"], "postprocess": (d) => makeRelativeDate("future", makeDuration(parseWordNumber(d[0]) * 2, "week")) },
661
+ { "name": "relativeDate", "symbols": ["number", "_", "fortnightKeyword", "_", "fromConnector", "_", "now"], "postprocess": (d) => makeRelativeDate("future", makeDuration(d[0] * 2, "week")) },
662
+ { "name": "relativeDate", "symbols": ["fortnightKeyword", "_", "fromConnector", "_", "now"], "postprocess": (d) => makeRelativeDate("future", makeDuration(2, "week")) },
663
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "wordNumber", "_", "fortnightKeyword"], "postprocess": (d) => makeRelativeDate("future", makeDuration(parseWordNumber(d[2]) * 2, "week")) },
664
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "number", "_", "fortnightKeyword"], "postprocess": (d) => makeRelativeDate("future", makeDuration(d[2] * 2, "week")) },
665
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "fortnightKeyword"], "postprocess": (d) => makeRelativeDate("future", makeDuration(2, "week")) },
666
+ { "name": "relativeDate", "symbols": ["wordNumber", "_", "fortnightKeyword", "_", "agoConnector"], "postprocess": (d) => makeRelativeDate("past", makeDuration(parseWordNumber(d[0]) * 2, "week")) },
667
+ { "name": "relativeDate", "symbols": ["number", "_", "fortnightKeyword", "_", "agoConnector"], "postprocess": (d) => makeRelativeDate("past", makeDuration(d[0] * 2, "week")) },
668
+ { "name": "relativeDate", "symbols": ["fortnightKeyword", "_", "agoConnector"], "postprocess": (d) => makeRelativeDate("past", makeDuration(2, "week")) },
657
669
  { "name": "fuzzy", "symbols": ["quarter"], "postprocess": (d) => makeFuzzy({ period: "quarter", quarter: parseQuarter(d[0].value) }) },
658
670
  { "name": "fuzzy", "symbols": ["quarter", "_", "year"], "postprocess": (d) => makeFuzzy({ period: "quarter", quarter: parseQuarter(d[0].value), year: d[2] }) },
659
671
  { "name": "fuzzy", "symbols": ["half"], "postprocess": (d) => makeFuzzy({ period: "half", half: parseHalf(d[0].value) }) },
@@ -754,11 +766,13 @@ var grammar = {
754
766
  { "name": "fuzzy", "symbols": ["lastRelative", "_", "nightKeyword"], "postprocess": (d) => makeFuzzy({ period: "night", relative: "last" }) },
755
767
  { "name": "fuzzy", "symbols": ["tomorrow", "_", "nightKeyword"], "postprocess": (d) => makeFuzzy({ period: "night", relative: "tomorrow" }) },
756
768
  { "name": "fuzzy", "symbols": ["weekday", "_", "nightKeyword"], "postprocess": (d) => makeFuzzy({ period: "night", weekday: d[0] }) },
757
- { "name": "fuzzy", "symbols": ["fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight" }) },
758
- { "name": "fuzzy", "symbols": ["nextRelative", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", relative: "next" }) },
759
- { "name": "fuzzy", "symbols": ["lastRelative", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", relative: "last" }) },
760
- { "name": "fuzzy", "symbols": ["inConnector", "_", "wordNumber", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", count: parseWordNumber(d[2]) }) },
761
- { "name": "fuzzy", "symbols": ["inConnector", "_", "number", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", count: d[2] }) },
769
+ { "name": "fuzzy", "symbols": ["laterKeyword", "_", "today"], "postprocess": (d) => makeFuzzy({ period: "day", modifier: "later" }) },
770
+ { "name": "fuzzy", "symbols": ["earlierKeyword", "_", "today"], "postprocess": (d) => makeFuzzy({ period: "day", modifier: "earlier" }) },
771
+ { "name": "fuzzy", "symbols": ["laterKeyword", "_", "thisRelative", "_", "unit"], "postprocess": (d) => makeFuzzy({ period: d[4], modifier: "later", relative: "this" }) },
772
+ { "name": "fuzzy", "symbols": ["earlierKeyword", "_", "thisRelative", "_", "unit"], "postprocess": (d) => makeFuzzy({ period: d[4], modifier: "earlier", relative: "this" }) },
773
+ { "name": "fuzzy", "symbols": ["weekKeyword", "_", "number"], "postprocess": (d) => makeFuzzy({ period: "weekNumber", weekNumber: d[2] }) },
774
+ { "name": "fuzzy", "symbols": ["weekKeyword", "_", "number", "_", "year"], "postprocess": (d) => makeFuzzy({ period: "weekNumber", weekNumber: d[2], year: d[4] }) },
775
+ { "name": "fuzzy", "symbols": ["theConnector", "_", "weekKeyword", "_", "ofConnector", "_", "date"], "postprocess": (d) => makeFuzzy({ period: "weekOf", baseDate: d[6] }) },
762
776
  { "name": "duration", "symbols": ["number", "_", "unit"], "postprocess": (d) => makeDuration(d[0], d[2]) },
763
777
  { "name": "duration", "symbols": ["wordNumber", "_", "unit"], "postprocess": (d) => makeDuration(parseWordNumber(d[0]), d[2]) },
764
778
  { "name": "duration", "symbols": ["abbreviatedDuration"], "postprocess": (d) => d[0] },
@@ -802,6 +816,7 @@ var grammar = {
802
816
  { "name": "date", "symbols": ["yearOnly"], "postprocess": first },
803
817
  { "name": "date", "symbols": ["timeOnly"], "postprocess": first },
804
818
  { "name": "date", "symbols": ["dayOnly"], "postprocess": first },
819
+ { "name": "date", "symbols": ["eodCobDate"], "postprocess": first },
805
820
  { "name": "monthDayCompact", "symbols": [lexer.has("monthDayCompact") ? { type: "monthDayCompact" } : monthDayCompact], "postprocess": (d) => {
806
821
  const parsed = parseMonthDayCompact(d[0].value);
807
822
  return makeDate({ month: parsed.month, day: parsed.day });
@@ -820,6 +835,15 @@ var grammar = {
820
835
  { "name": "timeOnly", "symbols": ["timeWord"], "postprocess": (d) => makeDate({ time: { special: d[0] }, timeOnly: true }) },
821
836
  { "name": "dayOnly", "symbols": ["theConnector", "_", "dayNumber"], "postprocess": (d) => makeDate({ day: d[2], dayOnly: true }) },
822
837
  { "name": "dayOnly", "symbols": ["onConnector", "_", "theConnector", "_", "dayNumber"], "postprocess": (d) => makeDate({ day: d[4], dayOnly: true }) },
838
+ { "name": "eodCobDate", "symbols": ["eodKeyword"], "postprocess": (d) => makeDate({ special: "today", time: { hour: 23, minute: 59 } }) },
839
+ { "name": "eodCobDate", "symbols": ["cobKeyword"], "postprocess": (d) => makeDate({ special: "today", time: { hour: 17, minute: 0 } }) },
840
+ { "name": "eodCobDate", "symbols": ["eodKeyword", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], time: { hour: 23, minute: 59 } }) },
841
+ { "name": "eodCobDate", "symbols": ["cobKeyword", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], time: { hour: 17, minute: 0 } }) },
842
+ { "name": "eodCobDate", "symbols": ["eodKeyword", "_", "specialDay"], "postprocess": (d) => makeDate({ special: d[2], time: { hour: 23, minute: 59 } }) },
843
+ { "name": "eodCobDate", "symbols": ["cobKeyword", "_", "specialDay"], "postprocess": (d) => makeDate({ special: d[2], time: { hour: 17, minute: 0 } }) },
844
+ { "name": "eodCobDate", "symbols": ["endConnector", "_", "ofConnector", "_", "dayUnit", "_", "specialDay"], "postprocess": (d) => makeDate({ special: d[6], time: { hour: 23, minute: 59 } }) },
845
+ { "name": "eodCobDate", "symbols": ["closeKeyword", "_", "ofConnector", "_", "businessKeyword", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[6], time: { hour: 17, minute: 0 } }) },
846
+ { "name": "eodCobDate", "symbols": ["closeKeyword", "_", "ofConnector", "_", "businessKeyword", "_", "specialDay"], "postprocess": (d) => makeDate({ special: d[6], time: { hour: 17, minute: 0 } }) },
823
847
  { "name": "specialDay", "symbols": ["today"], "postprocess": (d) => "today" },
824
848
  { "name": "specialDay", "symbols": ["tomorrow"], "postprocess": (d) => "tomorrow" },
825
849
  { "name": "specialDay", "symbols": ["yesterday"], "postprocess": (d) => "yesterday" },
@@ -829,6 +853,7 @@ var grammar = {
829
853
  { "name": "specialDay", "symbols": ["theConnector", "_", "dayUnit", "_", "beforeConnector", "_", "yesterday"], "postprocess": (d) => "dayBeforeYesterday" },
830
854
  { "name": "specialDay", "symbols": ["dayUnit", "_", "beforeConnector", "_", "yesterday"], "postprocess": (d) => "dayBeforeYesterday" },
831
855
  { "name": "dayUnit", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d, _, reject) => d[0].value === "day" ? d[0] : reject },
856
+ { "name": "dayOrDaysUnit", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d, _, reject) => d[0].value === "day" || d[0].value === "days" ? d[0] : reject },
832
857
  { "name": "relativeWeekday", "symbols": ["nextRelative", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], relative: "next" }) },
833
858
  { "name": "relativeWeekday", "symbols": ["lastRelative", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], relative: "last" }) },
834
859
  { "name": "relativeWeekday", "symbols": ["thisRelative", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], relative: "this" }) },
@@ -872,6 +897,9 @@ var grammar = {
872
897
  { "name": "dateWithTime", "symbols": ["time", "_", "date"], "postprocess": (d) => ({ ...d[2], time: d[0] }) },
873
898
  { "name": "dateWithTime", "symbols": ["timeWord", "_", "date"], "postprocess": (d) => ({ ...d[2], time: { special: d[0] } }) },
874
899
  { "name": "dateWithTime", "symbols": ["date", "_", "time"], "postprocess": (d) => ({ ...d[0], time: d[2] }) },
900
+ { "name": "dateWithTime", "symbols": ["timeWord", "_", "onConnector", "_", "date"], "postprocess": (d) => ({ ...d[4], time: { special: d[0] } }) },
901
+ { "name": "dateWithTime", "symbols": ["timeWord", "_", "onConnector", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[4], time: { special: d[0] } }) },
902
+ { "name": "dateWithTime", "symbols": ["midnight", "_", "tonightKeyword"], "postprocess": (d) => makeDate({ special: "tonight", time: { special: "midnight" } }) },
875
903
  { "name": "complexDate", "symbols": ["nextRelative", "_", "unit", "_", "weekday", "_", "time"], "postprocess": (d) => makeDate({ relative: "next", period: d[2], weekday: d[4], time: d[6] }) },
876
904
  { "name": "complexDate", "symbols": ["nextRelative", "_", "unit", "_", "weekday"], "postprocess": (d) => makeDate({ relative: "next", period: d[2], weekday: d[4] }) },
877
905
  { "name": "complexDate", "symbols": ["lastRelative", "_", "unit", "_", "weekday", "_", "time"], "postprocess": (d) => makeDate({ relative: "last", period: d[2], weekday: d[4], time: d[6] }) },
@@ -908,6 +936,45 @@ var grammar = {
908
936
  if (d[1].value === "am" && hour === 12) hour = 0;
909
937
  return { hour, minute: 0 };
910
938
  } },
939
+ { "name": "time", "symbols": ["quarterKeyword", "_", "pastConnector", "_", "hourNumber"], "postprocess": (d) => ({ hour: d[4], minute: 15 }) },
940
+ { "name": "time", "symbols": ["quarterKeyword", "_", "pastConnector", "_", "hourNumber", lexer.has("ampm") ? { type: "ampm" } : ampm], "postprocess": (d) => {
941
+ let hour = d[4];
942
+ if (d[5].value === "pm" && hour !== 12) hour += 12;
943
+ if (d[5].value === "am" && hour === 12) hour = 0;
944
+ return { hour, minute: 15 };
945
+ } },
946
+ { "name": "time", "symbols": ["halfWord", "_", "pastConnector", "_", "hourNumber"], "postprocess": (d) => ({ hour: d[4], minute: 30 }) },
947
+ { "name": "time", "symbols": ["halfWord", "_", "pastConnector", "_", "hourNumber", lexer.has("ampm") ? { type: "ampm" } : ampm], "postprocess": (d) => {
948
+ let hour = d[4];
949
+ if (d[5].value === "pm" && hour !== 12) hour += 12;
950
+ if (d[5].value === "am" && hour === 12) hour = 0;
951
+ return { hour, minute: 30 };
952
+ } },
953
+ { "name": "time", "symbols": ["quarterKeyword", "_", "toConnector", "_", "hourNumber"], "postprocess": (d) => ({ hour: d[4] - 1, minute: 45 }) },
954
+ { "name": "time", "symbols": ["quarterKeyword", "_", "toConnector", "_", "hourNumber", lexer.has("ampm") ? { type: "ampm" } : ampm], "postprocess": (d) => {
955
+ let hour = d[4];
956
+ if (d[5].value === "pm" && hour !== 12) hour += 12;
957
+ if (d[5].value === "am" && hour === 12) hour = 0;
958
+ return { hour: hour - 1, minute: 45 };
959
+ } },
960
+ { "name": "time", "symbols": ["number", "_", "pastConnector", "_", "hourNumber"], "postprocess": (d) => ({ hour: d[4], minute: d[0] }) },
961
+ { "name": "time", "symbols": ["number", "_", "pastConnector", "_", "hourNumber", lexer.has("ampm") ? { type: "ampm" } : ampm], "postprocess": (d) => {
962
+ let hour = d[4];
963
+ if (d[5].value === "pm" && hour !== 12) hour += 12;
964
+ if (d[5].value === "am" && hour === 12) hour = 0;
965
+ return { hour, minute: d[0] };
966
+ } },
967
+ { "name": "time", "symbols": ["number", "_", "toConnector", "_", "hourNumber"], "postprocess": (d) => ({ hour: d[4] - 1, minute: 60 - d[0] }) },
968
+ { "name": "time", "symbols": ["number", "_", "toConnector", "_", "hourNumber", lexer.has("ampm") ? { type: "ampm" } : ampm], "postprocess": (d) => {
969
+ let hour = d[4];
970
+ if (d[5].value === "pm" && hour !== 12) hour += 12;
971
+ if (d[5].value === "am" && hour === 12) hour = 0;
972
+ return { hour: hour - 1, minute: 60 - d[0] };
973
+ } },
974
+ { "name": "time", "symbols": ["number", "_", "toConnector", "_", "noon"], "postprocess": (d) => ({ hour: 11, minute: 60 - d[0] }) },
975
+ { "name": "time", "symbols": ["number", "_", "toConnector", "_", "midnight"], "postprocess": (d) => ({ hour: 23, minute: 60 - d[0] }) },
976
+ { "name": "time", "symbols": ["quarterKeyword", "_", "toConnector", "_", "noon"], "postprocess": (d) => ({ hour: 11, minute: 45 }) },
977
+ { "name": "time", "symbols": ["quarterKeyword", "_", "toConnector", "_", "midnight"], "postprocess": (d) => ({ hour: 23, minute: 45 }) },
911
978
  { "name": "timeWord", "symbols": ["noon"], "postprocess": (d) => "noon" },
912
979
  { "name": "timeWord", "symbols": ["midnight"], "postprocess": (d) => "midnight" },
913
980
  { "name": "number", "symbols": [lexer.has("integer") ? { type: "integer" } : integer], "postprocess": (d) => parseInt(d[0].value, 10) },
@@ -1004,10 +1071,28 @@ var grammar = {
1004
1071
  { "name": "now", "symbols": [lexer.has("kw_now") ? { type: "kw_now" } : kw_now], "postprocess": first },
1005
1072
  { "name": "noon", "symbols": [lexer.has("kw_noon") ? { type: "kw_noon" } : kw_noon], "postprocess": first },
1006
1073
  { "name": "midnight", "symbols": [lexer.has("kw_midnight") ? { type: "kw_midnight" } : kw_midnight], "postprocess": first },
1074
+ { "name": "quarterKeyword", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d, _, reject) => d[0].value === "quarter" ? d[0] : reject },
1075
+ { "name": "hourNumber", "symbols": [lexer.has("integer") ? { type: "integer" } : integer], "postprocess": (d, _, reject) => {
1076
+ const val = parseInt(d[0].value, 10);
1077
+ if (val < 1 || val > 12) return reject;
1078
+ return val;
1079
+ } },
1080
+ { "name": "pastConnector", "symbols": [lexer.has("kw_past") ? { type: "kw_past" } : kw_past], "postprocess": first },
1007
1081
  { "name": "weekendKeyword", "symbols": [lexer.has("kw_weekend") ? { type: "kw_weekend" } : kw_weekend], "postprocess": first },
1008
1082
  { "name": "tonightKeyword", "symbols": [lexer.has("kw_tonight") ? { type: "kw_tonight" } : kw_tonight], "postprocess": first },
1009
1083
  { "name": "nightKeyword", "symbols": [lexer.has("kw_night") ? { type: "kw_night" } : kw_night], "postprocess": first },
1010
1084
  { "name": "fortnightKeyword", "symbols": [lexer.has("kw_fortnight") ? { type: "kw_fortnight" } : kw_fortnight], "postprocess": first },
1085
+ { "name": "laterKeyword", "symbols": [lexer.has("otherKeyword") ? { type: "otherKeyword" } : otherKeyword], "postprocess": (d, _, reject) => d[0].value === "later" ? d[0] : reject },
1086
+ { "name": "earlierKeyword", "symbols": [lexer.has("otherKeyword") ? { type: "otherKeyword" } : otherKeyword], "postprocess": (d, _, reject) => d[0].value === "earlier" ? d[0] : reject },
1087
+ { "name": "weekKeyword", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d, _, reject) => {
1088
+ const val = d[0].value.toLowerCase();
1089
+ if (val === "week" || val === "weeks") return d[0];
1090
+ return reject;
1091
+ } },
1092
+ { "name": "businessKeyword", "symbols": [lexer.has("kw_business") ? { type: "kw_business" } : kw_business], "postprocess": first },
1093
+ { "name": "eodKeyword", "symbols": [lexer.has("kw_eod") ? { type: "kw_eod" } : kw_eod], "postprocess": first },
1094
+ { "name": "cobKeyword", "symbols": [lexer.has("kw_cob") ? { type: "kw_cob" } : kw_cob], "postprocess": first },
1095
+ { "name": "closeKeyword", "symbols": [lexer.has("kw_close") ? { type: "kw_close" } : kw_close], "postprocess": first },
1011
1096
  { "name": "_$ebnf$1", "symbols": [] },
1012
1097
  { "name": "_$ebnf$1", "symbols": ["_$ebnf$1", lexer.has("ws") ? { type: "ws" } : ws], "postprocess": (d) => d[0].concat([d[1]]) },
1013
1098
  { "name": "_", "symbols": ["_$ebnf$1"], "postprocess": nuller }
@@ -1753,6 +1838,42 @@ function getBasePeriodDates(node, opts, year) {
1753
1838
  const end = new Date(start.getTime() + 6 * MS_PER_DAY);
1754
1839
  return { start, end };
1755
1840
  }
1841
+ if (node.period === "weekNumber" && node.weekNumber !== void 0) {
1842
+ const weekNum = node.weekNumber;
1843
+ const targetYear = node.year ?? ref.getUTCFullYear();
1844
+ const weekStart = opts.weekStartsOn === "monday" ? 1 : 0;
1845
+ const jan1 = new Date(Date.UTC(targetYear, 0, 1));
1846
+ const jan1Day = jan1.getUTCDay();
1847
+ const daysToFirstWeekStart = (weekStart - jan1Day + 7) % 7;
1848
+ const firstWeekStart = new Date(jan1.getTime() + daysToFirstWeekStart * MS_PER_DAY);
1849
+ const start = new Date(firstWeekStart.getTime() + (weekNum - 1) * MS_PER_WEEK);
1850
+ const end = new Date(start.getTime() + 6 * MS_PER_DAY);
1851
+ return { start, end };
1852
+ }
1853
+ if (node.period === "weekOf" && node.baseDate) {
1854
+ const baseDate = node.baseDate;
1855
+ let targetDate;
1856
+ if (baseDate.month !== void 0 && baseDate.day !== void 0) {
1857
+ const month2 = typeof baseDate.month === "number" ? baseDate.month - 1 : 0;
1858
+ const day = baseDate.day;
1859
+ const targetYear = baseDate.year ?? ref.getUTCFullYear();
1860
+ targetDate = new Date(Date.UTC(targetYear, month2, day));
1861
+ } else {
1862
+ targetDate = ref;
1863
+ }
1864
+ const weekStart = opts.weekStartsOn === "monday" ? 1 : 0;
1865
+ const currentDay = targetDate.getUTCDay();
1866
+ const daysFromStart = (currentDay - weekStart + 7) % 7;
1867
+ const start = new Date(
1868
+ Date.UTC(
1869
+ targetDate.getUTCFullYear(),
1870
+ targetDate.getUTCMonth(),
1871
+ targetDate.getUTCDate() - daysFromStart
1872
+ )
1873
+ );
1874
+ const end = new Date(start.getTime() + 6 * MS_PER_DAY);
1875
+ return { start, end };
1876
+ }
1756
1877
  if (node.period === "day") {
1757
1878
  const start = new Date(
1758
1879
  Date.UTC(ref.getUTCFullYear(), ref.getUTCMonth(), ref.getUTCDate())
@@ -1916,7 +2037,7 @@ function convertASTToResult(ast, opts, originalInput) {
1916
2037
  const periodDates = convertFuzzyNodeWithoutModifier(expression, opts);
1917
2038
  return { type: "date", date: periodDates.end, title };
1918
2039
  }
1919
- if (period === "weekend" || period === "night" || period === "tonight" || period === "fortnight") {
2040
+ if (period === "weekend" || period === "night" || period === "tonight" || period === "fortnight" || period === "weekNumber" || period === "weekOf") {
1920
2041
  const duration = end.getTime() - start.getTime();
1921
2042
  return { type: "span", start, end, duration, title };
1922
2043
  }
@@ -1970,6 +2091,16 @@ function convertASTToResult(ast, opts, originalInput) {
1970
2091
  baseDate.getUTCMinutes()
1971
2092
  )
1972
2093
  );
2094
+ } else if (durationUnit === "businessDay" || durationUnit === "businessday") {
2095
+ resultDate = new Date(Date.UTC(baseDate.getUTCFullYear(), baseDate.getUTCMonth(), baseDate.getUTCDate()));
2096
+ let daysToAdd = durationValue;
2097
+ while (daysToAdd > 0) {
2098
+ resultDate.setUTCDate(resultDate.getUTCDate() + direction);
2099
+ const dayOfWeek = resultDate.getUTCDay();
2100
+ if (dayOfWeek !== 0 && dayOfWeek !== 6) {
2101
+ daysToAdd--;
2102
+ }
2103
+ }
1973
2104
  } else {
1974
2105
  const durationMs = convertDurationNode(durationNode);
1975
2106
  resultDate = new Date(baseDate.getTime() + direction * durationMs);