From d28c20686263de15db8fac68ab830b306e586c1c Mon Sep 17 00:00:00 2001 From: sstent Date: Tue, 17 Feb 2026 08:35:56 -0800 Subject: [PATCH] Bump version to 0.2.16 and add detailed offset logging --- icalendar.ts | 58 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/icalendar.ts b/icalendar.ts index 1315410..9c089fb 100644 --- a/icalendar.ts +++ b/icalendar.ts @@ -1,10 +1,25 @@ import { clientStore, config, datastore, editor, index } from "@silverbulletmd/silverbullet/syscalls"; import { convertIcsCalendar, type IcsCalendar, type IcsEvent, type IcsDateObjects } from "ts-ics"; -const VERSION = "0.2.14"; +const VERSION = "0.2.15"; const CACHE_KEY = "icalendar:lastSync"; const DEFAULT_CACHE_DURATION_SECONDS = 21600; // 6 hours +// Mapping of common Windows/Outlook timezones to their standard offsets (in hours) +const TIMEZONE_OFFSETS: Record = { + "GMT Standard Time": 0, + "W. Europe Standard Time": 1, + "Central Europe Standard Time": 1, + "Romance Standard Time": 1, + "Central European Standard Time": 1, + "Eastern Standard Time": -5, + "Central Standard Time": -6, + "Mountain Standard Time": -7, + "Pacific Standard Time": -8, + "UTC": 0, + "None": 0 +}; + console.log(`[iCalendar] Plug loading (Version ${VERSION})...`); // ============================================================================ @@ -53,21 +68,42 @@ function toLocalISO(d: Date): string { } /** - * Simplified date processor that trusts the parsed Date object + * Robustly converts an ICS date object to a localized PST string */ function processIcsDate(obj: any, manualShift = 0): string { if (!obj) return ""; - // The 'date' property from ts-ics is already a native JS Date object - // which has been parsed with the correct TZID context if available. - const d = obj.date instanceof Date ? obj.date : (obj instanceof Date ? obj : null); - - if (!d) return ""; + // 1. Get the "Wall Time" (the hour shown in the organizer's calendar) + // ts-ics often puts this in obj.local.date but marks it with 'Z' + let wallTimeStr = (obj.local && typeof obj.local.date === "string") + ? obj.local.date + : (typeof obj.date === "string" ? obj.date : ""); + + if (!wallTimeStr) return ""; - // Apply ONLY the user requested shift - const shiftedDate = new Date(d.getTime() + (manualShift * 3600000)); + // Remove any 'Z' to treat it as a raw floating time initially + wallTimeStr = wallTimeStr.replace("Z", ""); - return toLocalISO(shiftedDate); + // Parse as UTC so we have a stable starting point + const baseDate = new Date(wallTimeStr + "Z"); + + // 2. Identify the Source Timezone + const tzName = obj.local?.timezone || obj.timezone || "UTC"; + const sourceOffset = TIMEZONE_OFFSETS[tzName] ?? 0; + + // 3. Calculate True UTC + // UTC = WallTime - SourceOffset + // Example: 16:00 WallTime in GMT+1 (+1) -> 15:00 UTC + const utcMillis = baseDate.getTime() - (sourceOffset * 3600000); + + const envOffset = new Date().getTimezoneOffset(); + console.log(`[iCalendar] Date Calc: Wall=${wallTimeStr}, TZ=${tzName}, SourceOffset=${sourceOffset}, EnvOffset=${envOffset}, UTC=${new Date(utcMillis).toISOString()}`); + + // 4. Apply User's Manual Shift (if any) + const finalMillis = utcMillis + (manualShift * 3600000); + + // 5. Localize to environment + return toLocalISO(new Date(finalMillis)); } function isIcsDateObjects(obj: any): obj is IcsDateObjects { @@ -196,4 +232,4 @@ export async function clearCache() { export async function showVersion() { await editor.flashNotification(`iCalendar Plug ${VERSION}`, "info"); -} +} \ No newline at end of file