Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,17 @@ export default class ICSFeedCalendarService implements Calendar {
// if (vevent?.getFirstPropertyValue("transp") === "TRANSPARENT") return;

const event = new ICAL.Event(vevent);
// Fix timezone extraction - get TZID from DTSTART property parameters
const dtstartProperty = vevent.getFirstProperty("dtstart");
const tzidFromDtstart = dtstartProperty?.getParameter("tzid");

const dtstart: { [key: string]: string } | undefined = vevent?.getFirstPropertyValue("dtstart");
const timezone = dtstart ? dtstart["timezone"] : undefined;
// We check if the dtstart timezone is in UTC which is actually represented by Z instead, but not recognized as that in ICAL.js as UTC
const isUTC = timezone === "Z";
const tzid: string | undefined = vevent?.getFirstPropertyValue("tzid") || isUTC ? "UTC" : timezone;

// Fix precedence: prioritize TZID from DTSTART property, then check for UTC, then fallback
const tzid: string | undefined = tzidFromDtstart || vevent?.getFirstPropertyValue("tzid") || (isUTC ? "UTC" : timezone);
// In case of icalendar, when only tzid is available without vtimezone, we need to add vtimezone explicitly to take care of timezone diff
if (!vcalendar.getFirstSubcomponent("vtimezone")) {
const timezoneToUse = tzid || userTimeZone;
Expand Down
7 changes: 6 additions & 1 deletion packages/lib/CalendarService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,11 +393,16 @@ export default abstract class BaseCalendarService implements Calendar {
if (vevent?.getFirstPropertyValue("transp") === "TRANSPARENT") return;

const event = new ICAL.Event(vevent);
// Fix timezone extraction - get TZID from DTSTART property parameters
const dtstartProperty = vevent.getFirstProperty("dtstart");
const tzidFromDtstart = dtstartProperty?.getParameter("tzid");
const dtstart: { [key: string]: string } | undefined = vevent?.getFirstPropertyValue("dtstart");
const timezone = dtstart ? dtstart["timezone"] : undefined;
// We check if the dtstart timezone is in UTC which is actually represented by Z instead, but not recognized as that in ICAL.js as UTC
const isUTC = timezone === "Z";
const tzid: string | undefined = vevent?.getFirstPropertyValue("tzid") || isUTC ? "UTC" : timezone;

// Fix precedence: prioritize TZID from DTSTART property, then check for UTC, then fallback
const tzid: string | undefined = tzidFromDtstart || (isUTC ? "UTC" : timezone);
// In case of icalendar, when only tzid is available without vtimezone, we need to add vtimezone explicitly to take care of timezone diff
if (!vcalendar.getFirstSubcomponent("vtimezone")) {
const timezoneToUse = tzid || userTimeZone;
Expand Down
Loading