diff --git a/STATUS.md b/STATUS.md index f78a3b1..5fcd1bf 100644 --- a/STATUS.md +++ b/STATUS.md @@ -65,7 +65,7 @@ ### Day helpers -- [ ] `addBusinessDays` +- [x] `addBusinessDays` - [x] `addDays` - [x] `subDays` - [ ] `differenceInBusinessDays` diff --git a/__tests__/addBusinessDays_test.re b/__tests__/addBusinessDays_test.re new file mode 100644 index 0000000..2db9bd9 --- /dev/null +++ b/__tests__/addBusinessDays_test.re @@ -0,0 +1,56 @@ +open Jest; + +open Js.Date; + +describe("addBusinessDays", () => { + open ExpectJs; + + test("adds 0 business days", () => { + let date = makeWithYMD(~year=2020., ~month=0., ~date=1., ()); + let expectedDate = makeWithYMD(~year=2020., ~month=0., ~date=1., ()); + + date |> ReDate.addBusinessDays(0) |> expect |> toEqual(expectedDate); + }); + + test("adds 1 business day", () => { + let date = makeWithYMD(~year=2020., ~month=0., ~date=1., ()); + let expectedDate = makeWithYMD(~year=2020., ~month=0., ~date=2., ()); + + date |> ReDate.addBusinessDays(1) |> expect |> toEqual(expectedDate); + }); + + test("adds 100 business days", () => { + let date = makeWithYMD(~year=2020., ~month=0., ~date=1., ()); + let expectedDate = makeWithYMD(~year=2020., ~month=4., ~date=20., ()); + + date |> ReDate.addBusinessDays(100) |> expect |> toEqual(expectedDate); + }); + + test("handles negative number", () => { + let date = makeWithYMD(~year=2020., ~month=4., ~date=20., ()); + let expectedDate = makeWithYMD(~year=2020., ~month=0., ~date=1., ()); + + date |> ReDate.addBusinessDays(-100) |> expect |> toEqual(expectedDate); + }); + + test("returns Monday when 1 day is added on Friday", () => { + let date = makeWithYMD(~year=2020., ~month=0., ~date=10., ()); + let expectedDate = makeWithYMD(~year=2020., ~month=0., ~date=13., ()); + + date |> ReDate.addBusinessDays(1) |> expect |> toEqual(expectedDate); + }); + + test("returns Monday when 1 day is added on Saturday", () => { + let date = makeWithYMD(~year=2020., ~month=0., ~date=11., ()); + let expectedDate = makeWithYMD(~year=2020., ~month=0., ~date=13., ()); + + date |> ReDate.addBusinessDays(1) |> expect |> toEqual(expectedDate); + }); + + test("returns Monday when 1 day is added on Sunday", () => { + let date = makeWithYMD(~year=2020., ~month=0., ~date=12., ()); + let expectedDate = makeWithYMD(~year=2020., ~month=0., ~date=13., ()); + + date |> ReDate.addBusinessDays(1) |> expect |> toEqual(expectedDate); + }); +}); diff --git a/docs/day.md b/docs/day.md index 02d72fd..a3246a0 100644 --- a/docs/day.md +++ b/docs/day.md @@ -12,6 +12,18 @@ let date = Js.Date.makeWithYMD(~year=2018., ~month=0., ~date=1., ()); date |> ReDate.addDays(5); ``` +#### addBusinessDays + +> Add the specified number of business days to the given date (excluding weekends). + +`let addBusinessDays: (int, Js.Date.t) => Js.Date.t` + +```reason +let date = Js.Date.makeWithYMD(~year=2018., ~month=0., ~date=1., ()); + +date |> ReDate.addBusinessDays(5); +``` + #### subDays > Subtract the specified number of days from the given date. diff --git a/src/ReDate.re b/src/ReDate.re index 73484d9..21f6498 100644 --- a/src/ReDate.re +++ b/src/ReDate.re @@ -470,6 +470,19 @@ let isSameHour = (fst, snd) => let addDays = Internal.addDays; +let rec addBusinessDays = (days, date) => { + let next = days < 0 ? succ : pred; + let sign = days < 0 ? (-1) : 1; + let date = date |> addDays(sign); + + if (Internal.isWeekend(date)) { + date |> addBusinessDays(days); + } else { + days == 0 + ? date |> addDays(- sign) : date |> addBusinessDays(days |> next); + }; +}; + let subDays = (days, date) => date |> addDays(- days); let startOfDay = Internal.makeDateWithStartOfDayHours; diff --git a/src/ReDate.rei b/src/ReDate.rei index 321f841..7e293f2 100644 --- a/src/ReDate.rei +++ b/src/ReDate.rei @@ -98,6 +98,8 @@ let isSameHour: (Js.Date.t, Js.Date.t) => bool; /* ——[Day helpers——————————— */ +let addBusinessDays: (int, Js.Date.t) => Js.Date.t; + let addDays: (int, Js.Date.t) => Js.Date.t; let subDays: (int, Js.Date.t) => Js.Date.t;