Bugfix/5271 wrong availability displayed on nov 6 (#5365)
* Fixes the localisation issue with recurring events * Implement DST as Dayjs doesn't * Fixed generated booking URL when different TZ is set * manually apply DST offset to times * Fix type error
This commit is contained in:
parent
328a354f4d
commit
db9911a264
|
@ -83,7 +83,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||
pathname: router.pathname.endsWith("/embed") ? "../book" : "book",
|
||||
query: {
|
||||
...router.query,
|
||||
date: dayjs(slot.time).format(),
|
||||
date: dayjs.utc(slot.time).tz(timeZone()).format(),
|
||||
type: eventTypeId,
|
||||
slug: eventTypeSlug,
|
||||
/** Treat as recurring only when a count exist and it's not a rescheduling workflow */
|
||||
|
|
|
@ -497,26 +497,17 @@ const BookingPage = ({
|
|||
<div className="text-bookinghighlight flex items-start text-sm">
|
||||
<Icon.FiCalendar className="mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4" />
|
||||
<div className="text-sm font-medium">
|
||||
{(rescheduleUid || !eventType.recurringEvent?.freq) &&
|
||||
`${formatTime(dayjs(date).toDate(), user?.timeFormat, user?.timeZone)}, ${dayjs(
|
||||
date
|
||||
).format("dddd, D MMMM YYYY")}`}
|
||||
{(rescheduleUid || !eventType.recurringEvent?.freq) && `${parseDate(date, i18n)}`}
|
||||
{!rescheduleUid &&
|
||||
eventType.recurringEvent?.freq &&
|
||||
recurringDates.slice(0, 5).map((aDate, key) => {
|
||||
return (
|
||||
<p key={key}>{`${formatTime(aDate, user?.timeFormat, user?.timeZone)}, ${dayjs(
|
||||
aDate
|
||||
).format("dddd, D MMMM YYYY")}`}</p>
|
||||
);
|
||||
recurringStrings.slice(0, 5).map((timeFormatted, key) => {
|
||||
return <p key={key}>{timeFormatted}</p>;
|
||||
})}
|
||||
{!rescheduleUid && eventType.recurringEvent?.freq && recurringStrings.length > 5 && (
|
||||
<div className="flex">
|
||||
<Tooltip
|
||||
content={recurringDates.slice(5).map((aDate, key) => (
|
||||
<p key={key}>{`${formatTime(aDate, user?.timeFormat, user?.timeZone)}, ${dayjs(
|
||||
aDate
|
||||
).format("dddd, D MMMM YYYY")}`}</p>
|
||||
content={recurringStrings.slice(5).map((timeFormatted, key) => (
|
||||
<p key={key}>{timeFormatted}</p>
|
||||
))}>
|
||||
<p className="dark:text-darkgray-600 text-sm">
|
||||
{t("plus_more", { count: recurringStrings.length - 5 })}
|
||||
|
|
|
@ -20,15 +20,6 @@ export const parseDate = (date: string | null | Dayjs, i18n: I18n) => {
|
|||
return processDate(date, i18n);
|
||||
};
|
||||
|
||||
// tzid is currently broken in rrule library.
|
||||
// @see https://github.com/jakubroztocil/rrule/issues/523
|
||||
const dateWithZone = (d: Date, timeZone?: string) => {
|
||||
const dateInLocalTZ = new Date(d.toLocaleString("en-US", { timeZone: "UTC" }));
|
||||
const dateInTargetTZ = new Date(d.toLocaleString("en-US", { timeZone: timeZone || "UTC" }));
|
||||
const tzOffset = dateInTargetTZ.getTime() - dateInLocalTZ.getTime();
|
||||
return new Date(d.getTime() - tzOffset);
|
||||
};
|
||||
|
||||
export const parseRecurringDates = (
|
||||
{
|
||||
startDate,
|
||||
|
@ -48,16 +39,21 @@ export const parseRecurringDates = (
|
|||
const rule = new RRule({
|
||||
...restRecurringEvent,
|
||||
count: recurringCount,
|
||||
dtstart: dayjs(startDate).utc(true).toDate(),
|
||||
});
|
||||
// UTC times with tzOffset applied to account for DST
|
||||
const times = rule.all().map((t) => dateWithZone(t, timeZone));
|
||||
const dateStrings = times.map((t) => {
|
||||
// undo DST diffs for localized display.
|
||||
return processDate(dayjs.utc(t).tz(timeZone), i18n);
|
||||
dtstart: new Date(dayjs(startDate).valueOf()),
|
||||
});
|
||||
|
||||
return [dateStrings, times];
|
||||
const startUtcOffset = dayjs(startDate).utcOffset();
|
||||
// UTC still need to have DST applied, rrule does not do this.
|
||||
const times = rule.all().map((t) => {
|
||||
// applying the DST offset.
|
||||
return dayjs.utc(t).add(startUtcOffset - dayjs(t).utcOffset(), "minute");
|
||||
});
|
||||
const dateStrings = times.map((t) => {
|
||||
// finally; show in local timeZone again
|
||||
return processDate(t.tz(timeZone), i18n);
|
||||
});
|
||||
|
||||
return [dateStrings, times.map((t) => t.toDate())];
|
||||
};
|
||||
|
||||
export const extractRecurringDates = (
|
||||
|
|
|
@ -111,7 +111,24 @@ const getSlots = ({ inviteeDate, frequency, minimumBookingNotice, workingHours,
|
|||
});
|
||||
|
||||
slotsTimeFrameAvailable.forEach((item) => {
|
||||
const slot = startOfInviteeDay.add(item.startTime, "minute");
|
||||
// XXX: Hack alert, as dayjs is supposedly not aware of timezone the current slot may have invalid UTC offset.
|
||||
const timeZone = (startOfInviteeDay as unknown as { $x: { $timezone: string } })["$x"]["$timezone"];
|
||||
/*
|
||||
* @calcom/web:dev: 2022-11-06T00:00:00-04:00
|
||||
* @calcom/web:dev: 2022-11-06T01:00:00-04:00
|
||||
* @calcom/web:dev: 2022-11-06T01:00:00-04:00 <-- note there is no offset change, but we did lose an hour.
|
||||
* @calcom/web:dev: 2022-11-06T02:00:00-04:00
|
||||
* @calcom/web:dev: 2022-11-06T03:00:00-04:00
|
||||
* ...
|
||||
*/
|
||||
let slot = dayjs.tz(
|
||||
startOfInviteeDay.add(item.startTime, "minute").format("YYYY-MM-DDTHH:mm:ss"),
|
||||
timeZone
|
||||
);
|
||||
// If the startOfInviteeDay has a different UTC offset than the slot, a DST change has occurred.
|
||||
// As the time has now fallen backwards, or forwards; this difference -
|
||||
// needs to be manually added as this is not done for us. Usually 0.
|
||||
slot = slot.add(startOfInviteeDay.utcOffset() - slot.utcOffset(), "minutes");
|
||||
// Validating slot its not on the past
|
||||
if (!slot.isBefore(startDate)) {
|
||||
slots.push(slot);
|
||||
|
|
Loading…
Reference in New Issue
Block a user