diff --git a/docs/widgets/services/calendar.md b/docs/widgets/services/calendar.md
index 74751f6e..bb8b5016 100644
--- a/docs/widgets/services/calendar.md
+++ b/docs/widgets/services/calendar.md
@@ -16,6 +16,7 @@ widget:
view: monthly # optional - possible values monthly, agenda
maxEvents: 10 # optional - defaults to 10
showTime: true # optional - show time for event happening today - defaults to false
+ timezone: America/Los_Angeles # optional and only when timezone is not detected properly (slightly slower performance) - force timezone for ical events (if it's the same - no change, if missing or different in ical - will be converted to this timezone)
integrations: # optional
- type: sonarr # active widget type that is currently enabled on homepage - possible values: radarr, sonarr, lidarr, readarr, ical
service_group: Media # group name where widget exists
@@ -27,7 +28,6 @@ widget:
url: https://domain.url/with/link/to.ics # URL with calendar events
name: My Events # required - name for these calendar events
color: zinc # optional - defaults to pre-defined color for the service (zinc for ical)
- timezone: America/Los_Angeles # optional - force timezone for events (if it's the same - no change, if missing or different in ical - will be converted to this timezone)
params: # optional - additional params for the service
showName: true # optional - show name before event title in event line - defaults to false
```
diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js
index b0854b08..cfc88fdc 100644
--- a/src/utils/config/service-helpers.js
+++ b/src/utils/config/service-helpers.js
@@ -368,6 +368,7 @@ export function cleanServiceGroups(groups) {
showTime,
previousDays,
view,
+ timezone,
// coinmarketcap
currency,
@@ -538,6 +539,7 @@ export function cleanServiceGroups(groups) {
if (maxEvents) cleanedService.widget.maxEvents = maxEvents;
if (previousDays) cleanedService.widget.previousDays = previousDays;
if (showTime) cleanedService.widget.showTime = showTime;
+ if (timezone) cleanedService.widget.timezone = timezone;
}
if (type === "healthchecks") {
if (uuid !== undefined) cleanedService.widget.uuid = uuid;
diff --git a/src/widgets/calendar/agenda.jsx b/src/widgets/calendar/agenda.jsx
index 9313cb8e..6a3be031 100644
--- a/src/widgets/calendar/agenda.jsx
+++ b/src/widgets/calendar/agenda.jsx
@@ -2,7 +2,7 @@ import { DateTime } from "luxon";
import classNames from "classnames";
import { useTranslation } from "next-i18next";
-import Event, { compareDateTimezoneAware } from "./event";
+import Event, { compareDateTimezone } from "./event";
export default function Agenda({ service, colorVariants, events, showDate }) {
const { widget } = service;
@@ -15,10 +15,8 @@ export default function Agenda({ service, colorVariants, events, showDate }) {
const eventsArray = Object.keys(events)
.filter(
(eventKey) =>
- showDate
- .setZone(events[eventKey].date.zoneName)
- .minus({ days: widget?.previousDays ?? 0 })
- .startOf("day").ts <= events[eventKey].date?.startOf("day").ts,
+ showDate.minus({ days: widget?.previousDays ?? 0 }).startOf("day").ts <=
+ events[eventKey].date?.startOf("day").ts,
)
.map((eventKey) => events[eventKey])
.sort((a, b) => a.date - b.date)
@@ -58,7 +56,7 @@ export default function Agenda({ service, colorVariants, events, showDate }) {
event={event}
colorVariants={colorVariants}
showDate={j === 0}
- showTime={widget?.showTime && compareDateTimezoneAware(showDate, event)}
+ showTime={widget?.showTime && compareDateTimezone(showDate, event)}
/>
))}
diff --git a/src/widgets/calendar/component.jsx b/src/widgets/calendar/component.jsx
index 0e10d0ed..ff93c41b 100644
--- a/src/widgets/calendar/component.jsx
+++ b/src/widgets/calendar/component.jsx
@@ -41,7 +41,8 @@ export default function Component({ service }) {
const { i18n } = useTranslation();
const [showDate, setShowDate] = useState(null);
const [events, setEvents] = useState({});
- const currentDate = DateTime.now().setLocale(i18n.language).startOf("day");
+ const nowDate = DateTime.now().setLocale(i18n.language);
+ const currentDate = widget?.timezone ? nowDate.setZone(widget?.timezone).startOf("day") : nowDate;
const { settings } = useContext(SettingsContext);
useEffect(() => {
@@ -93,6 +94,7 @@ export default function Component({ service }) {
params={params}
setEvents={setEvents}
hideErrors={settings.hideErrors}
+ timezone={widget?.timezone}
className="fixed bottom-0 left-0 bg-red-500 w-screen h-12"
/>
);
@@ -106,6 +108,7 @@ export default function Component({ service }) {
events={events}
showDate={showDate}
setShowDate={setShowDate}
+ currentDate={currentDate}
className="flex"
/>
)}
diff --git a/src/widgets/calendar/event.jsx b/src/widgets/calendar/event.jsx
index 7d348285..13e736a3 100644
--- a/src/widgets/calendar/event.jsx
+++ b/src/widgets/calendar/event.jsx
@@ -39,7 +39,4 @@ export default function Event({ event, colorVariants, showDate = false, showTime
);
}
-
-export function compareDateTimezoneAware(date, event) {
- return date.setZone(event.date.zoneName).startOf("day").valueOf() === event.date.startOf("day").valueOf();
-}
+export const compareDateTimezone = (date, event) => date.startOf("day").ts === event.date.startOf("day").ts;
diff --git a/src/widgets/calendar/integrations/ical.jsx b/src/widgets/calendar/integrations/ical.jsx
index 4c4ec9ca..78d0fe1d 100644
--- a/src/widgets/calendar/integrations/ical.jsx
+++ b/src/widgets/calendar/integrations/ical.jsx
@@ -7,7 +7,7 @@ import { RRule } from "rrule";
import useWidgetAPI from "../../../utils/proxy/use-widget-api";
import Error from "../../../components/services/widget/error";
-export default function Integration({ config, params, setEvents, hideErrors }) {
+export default function Integration({ config, params, setEvents, hideErrors, timezone }) {
const { t } = useTranslation();
const { data: icalData, error: icalError } = useWidgetAPI(config, config.name, {
refreshInterval: 300000, // 5 minutes
@@ -23,9 +23,8 @@ export default function Integration({ config, params, setEvents, hideErrors }) {
}
}
- const zone = config?.timezone || null;
- const startDate = DateTime.fromISO(params.start, { zone });
- const endDate = DateTime.fromISO(params.end, { zone });
+ const startDate = DateTime.fromISO(params.start);
+ const endDate = DateTime.fromISO(params.end);
if (icalError || !parsedIcal || !startDate.isValid || !endDate.isValid) {
return;
@@ -33,6 +32,7 @@ export default function Integration({ config, params, setEvents, hideErrors }) {
const eventsToAdd = {};
const events = parsedIcal?.getEventsBetweenDates(startDate.toJSDate(), endDate.toJSDate());
+ const now = timezone ? DateTime.now().setZone(timezone) : DateTime.now();
events?.forEach((event) => {
let title = `${event?.summary?.value}`;
@@ -44,8 +44,7 @@ export default function Integration({ config, params, setEvents, hideErrors }) {
const duration = event.dtend.value - event.dtstart.value;
const days = duration / (1000 * 60 * 60 * 24);
- const now = DateTime.now().setZone(zone);
- const eventDate = DateTime.fromJSDate(date, { zone });
+ const eventDate = timezone ? DateTime.fromJSDate(date, { zone: timezone }) : DateTime.fromJSDate(date);
for (let j = 0; j < days; j += 1) {
eventsToAdd[`${event?.uid?.value}${i}${j}${type}`] = {
@@ -72,7 +71,7 @@ export default function Integration({ config, params, setEvents, hideErrors }) {
});
setEvents((prevEvents) => ({ ...prevEvents, ...eventsToAdd }));
- }, [icalData, icalError, config, params, setEvents, t]);
+ }, [icalData, icalError, config, params, setEvents, timezone, t]);
const error = icalError ?? icalData?.error;
return error && !hideErrors &&