this repo has no description

UTC time zone fix in SVG?

+63 -13
+11 -1
components/WeeklySchedule.tsx
··· 1 1 import satori from "https://esm.sh/satori@0.12.1"; 2 2 import format from "https://deno.land/x/date_fns@v2.22.1/format/index.js"; 3 3 import { Event } from "../utils/calendarUtils.ts"; 4 + import { toZonedTime } from "npm:date-fns-tz"; 4 5 5 6 // Define theme interface for styling options 6 7 interface Theme { ··· 307 308 color: theme.eventTextColor, 308 309 }} 309 310 > 310 - {hasEvent ? format(event.start, "ha", []) : ""} 311 + {hasEvent 312 + ? format( 313 + toZonedTime( 314 + event.start, 315 + event.timezone!, 316 + ), 317 + "ha", 318 + [], 319 + ) 320 + : ""} 311 321 </div> 312 322 </div> 313 323 );
+11 -4
routes/api/fetch-calendar-text.ts
··· 1 1 import { Handlers } from "$fresh/server.ts"; 2 2 import { processCalendarRequest } from "../../utils/calendarUtils.ts"; 3 + import { toZonedTime } from "npm:date-fns-tz"; 3 4 4 5 export const handler: Handlers = { 5 6 async GET(req) { ··· 10 11 11 12 let formattedText = ""; 12 13 for (const event of events) { 13 - const startDate = new Date(event.start); 14 + const startDate = toZonedTime( 15 + new Date(event.start), 16 + event.timezone!, 17 + ); 14 18 const unixTimestamp = Math.floor(startDate.getTime() / 1000); 15 19 formattedText += 16 20 `\n- <t:${unixTimestamp}:F> | **${event.summary}**`; ··· 19 23 } 20 24 } 21 25 22 - return new Response(JSON.stringify({ result: formattedText.trim() }), { 23 - headers: { "Content-Type": "application/json" }, 24 - }); 26 + return new Response( 27 + JSON.stringify({ result: formattedText.trim() }), 28 + { 29 + headers: { "Content-Type": "application/json" }, 30 + }, 31 + ); 25 32 } catch (error) { 26 33 console.error("Error processing URL:", error); 27 34 return new Response(
+41 -8
utils/calendarUtils.ts
··· 5 5 import parseISO from "https://deno.land/x/date_fns@v2.22.1/parseISO/index.js"; 6 6 import startOfDay from "https://deno.land/x/date_fns@v2.22.1/startOfDay/index.ts"; 7 7 import endOfDay from "https://deno.land/x/date_fns@v2.22.1/endOfDay/index.ts"; 8 + import { fromZonedTime } from "npm:date-fns-tz"; 8 9 9 10 export interface Event { 10 11 start: Date; ··· 12 13 summary?: string; 13 14 location?: string; 14 15 description?: string; 16 + timezone?: string; 15 17 } 16 18 17 19 export interface TwitchEvent { ··· 56 58 57 59 // deno-lint-ignore no-explicit-any 58 60 function parseICalEvents(icalEvents: Record<string, any>): Event[] { 61 + // Extract calendar-level timezone if available 62 + const calendarTz = 63 + Object.values(icalEvents).find((item) => item.type === "VCALENDAR") 64 + ?.["x-wr-timezone"] || "UTC"; 65 + 59 66 return Object.values(icalEvents) 60 67 .filter((event) => event.type === "VEVENT") 61 - .map((event) => ({ 62 - start: event.start, 63 - end: event.end, 64 - location: event.location || "", 65 - summary: event.summary || "", 66 - description: event.description || "", 67 - })); 68 + .map((event) => { 69 + // Use event-specific timezone if available, otherwise fallback to calendar timezone 70 + const eventTz = event.startZone || calendarTz; 71 + 72 + // Convert dates to UTC for internal comparisons 73 + const start = normalizeDate(event.start, eventTz); 74 + const end = normalizeDate(event.end, eventTz); 75 + 76 + return { 77 + start, 78 + end, 79 + location: event.location || "", 80 + summary: event.summary || "", 81 + description: event.description || "", 82 + timezone: eventTz, 83 + }; 84 + }); 85 + } 86 + 87 + function normalizeDate(date: Date, timezone: string): Date { 88 + if (!date) return date; 89 + 90 + try { 91 + // Convert the date to UTC while respecting the original timezone 92 + return fromZonedTime(date, timezone); 93 + } catch (e) { 94 + console.warn(`Failed to parse timezone ${timezone}:`, e); 95 + return date; 96 + } 68 97 } 69 98 70 99 export function filterEvents( ··· 72 101 weekStart: Date, 73 102 weekEnd: Date, 74 103 ): Event[] { 104 + // Ensure weekStart and weekEnd are in UTC for comparison 105 + const utcWeekStart = new Date(weekStart.toISOString()); 106 + const utcWeekEnd = new Date(weekEnd.toISOString()); 107 + 75 108 const weeklyEvents = events.filter((event) => 76 - isAfter(event.start, weekStart) && isBefore(event.start, weekEnd) 109 + isAfter(event.start, utcWeekStart) && isBefore(event.start, utcWeekEnd) 77 110 ); 78 111 79 112 return weeklyEvents;