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
This commit is contained in:
Carina Wollendorfer 2023-10-11 18:30:35 +00:00 committed by GitHub
parent df29376b0e
commit 9d7d838131
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 6 deletions

View File

@ -92,8 +92,8 @@ const NoAvailabilityOverlay = ({
const { t } = useLocale();
return (
<div className=" bg-muted border-subtle absolute left-1/2 top-40 -mt-10 w-max -translate-x-1/2 -translate-y-1/2 transform rounded-md border p-8 shadow-sm">
<h4 className="text-emphasis mb-4 font-medium">{t("no_availability_in_month", { month: month })}</h4>
<div className="bg-muted border-subtle absolute left-1/2 top-40 -mt-10 w-max -translate-x-1/2 -translate-y-1/2 transform rounded-md border p-8 shadow-sm">
<h4 className="text-emphasis mb-4 font-medium">{t("no_availability_in_month", { month: month })}</h4>
<Button onClick={nextMonthButton} color="primary" EndIcon={ArrowRight}>
{t("view_next_month")}
</Button>
@ -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;

View File

@ -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

View File

@ -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