From 9d7d838131a1993a9a9486488d68f90b248bbcae Mon Sep 17 00:00:00 2001 From: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> Date: Wed, 11 Oct 2023 18:30:35 +0000 Subject: [PATCH] fix: missing last day of month ## What does this PR do? - Fix that the last day in Oktober was always shown as unavailable This happened when availability was in Europe/London timezone - Fix that the last day of November was always shown as unavailable This happened also for other timezones ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## How should this be tested? I recommend testing it in staging instead of local, as I experienced some different behaviors on local - Reproduce the 2 bugs as described before my fix - If you were able to reproduce it, see if it is fixed with my fixes in this PR (last day of octber and November should be shown as available) - Check if availability starts and ends at the correct time on days were DST happens --- packages/features/calendars/DatePicker.tsx | 9 ++++++--- packages/lib/date-ranges.test.ts | 19 +++++++++++++++++++ packages/lib/date-ranges.ts | 11 ++++++++--- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/packages/features/calendars/DatePicker.tsx b/packages/features/calendars/DatePicker.tsx index cf69e33ad4..e046aadcea 100644 --- a/packages/features/calendars/DatePicker.tsx +++ b/packages/features/calendars/DatePicker.tsx @@ -92,8 +92,8 @@ const NoAvailabilityOverlay = ({ const { t } = useLocale(); return ( -
-

{t("no_availability_in_month", { month: month })}

+
+

{t("no_availability_in_month", { month: month })}

@@ -139,7 +139,10 @@ const Days = ({ return dates; }; - const includedDates = currentDate.isSame(browsingDate, "month") + const utcBrowsingDateWithOffset = browsingDate.utc().add(browsingDate.utcOffset(), "minute"); + const utcCurrentDateWithOffset = currentDate.utc().add(browsingDate.utcOffset(), "minute"); + + const includedDates = utcCurrentDateWithOffset.isSame(utcBrowsingDateWithOffset, "month") ? availableDates(props.includedDates) : props.includedDates; diff --git a/packages/lib/date-ranges.test.ts b/packages/lib/date-ranges.test.ts index 1e87dd9a56..59a98d886f 100644 --- a/packages/lib/date-ranges.test.ts +++ b/packages/lib/date-ranges.test.ts @@ -29,6 +29,25 @@ describe("processWorkingHours", () => { end: dayjs(`${dateTo.tz(timeZone).format("YYYY-MM-DD")}T21:00:00Z`).tz(timeZone), }); }); + it("should have availability on last day of month in the month were DST starts", () => { + const item = { + days: [0, 1, 2, 3, 4, 5, 6], // Monday to Sunday + startTime: new Date(Date.UTC(2023, 5, 12, 8, 0)), // 8 AM + endTime: new Date(Date.UTC(2023, 5, 12, 17, 0)), // 5 PM + }; + + const timeZone = "Europe/London"; + + const dateFrom = dayjs().month(9).date(24); // starts before DST change + const dateTo = dayjs().startOf("day").month(10).date(1); // first day of November + + const results = processWorkingHours({ item, timeZone, dateFrom, dateTo }); + + const lastAvailableSlot = results[results.length - 1]; + + expect(lastAvailableSlot.start.date()).toBe(31); + }); + it("should return the correct working hours in the month were DST ends", () => { const item = { days: [0, 1, 2, 3, 4, 5, 6], // Monday to Sunday diff --git a/packages/lib/date-ranges.ts b/packages/lib/date-ranges.ts index 4fd5cf2f3c..324f82dd08 100644 --- a/packages/lib/date-ranges.ts +++ b/packages/lib/date-ranges.ts @@ -23,15 +23,20 @@ export function processWorkingHours({ }) { const results = []; for (let date = dateFrom.tz(timeZone).startOf("day"); dateTo.isAfter(date); date = date.add(1, "day")) { - const dateInTz = date.tz(timeZone); + const fromOffset = dateFrom.tz(timeZone).utcOffset(); + const offset = date.tz(timeZone).utcOffset(); + // it always has to be start of the day (midnight) even when DST changes + const dateInTz = date.add(fromOffset - offset, "minutes").tz(timeZone); if (!item.days.includes(dateInTz.day())) { continue; } - let start = dateInTz.hour(item.startTime.getUTCHours()).minute(item.startTime.getUTCMinutes()).second(0); + let start = dateInTz + .add(item.startTime.getUTCHours(), "hours") + .add(item.startTime.getUTCMinutes(), "minutes"); - let end = dateInTz.hour(item.endTime.getUTCHours()).minute(item.endTime.getUTCMinutes()).second(0); + let end = dateInTz.add(item.endTime.getUTCHours(), "hours").add(item.endTime.getUTCMinutes(), "minutes"); const offsetBeginningOfDay = dayjs(start.format("YYYY-MM-DD hh:mm")).tz(timeZone).utcOffset(); const offsetDiff = start.utcOffset() - offsetBeginningOfDay; // there will be 60 min offset on the day day of DST change