fix: Outlook event timezone offset on create/update responses

Outlook Graph API returns datetimes in the user's timezone without Z suffix
by default. The sync path already requested UTC and appended Z, but
create/update responses did not. This caused the optimistic UI update to
show events 1 hour off until the next sync corrected it.

Fix: add Prefer: outlook.timezone="UTC" header to create/update calls
and normalize response datetimes with Z suffix.

v1.71.3

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
mARTin 2026-03-25 00:03:17 +01:00
parent 92593cf616
commit 131f92bd72
2 changed files with 21 additions and 8 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "my-weekly-todo-list", "name": "my-weekly-todo-list",
"version": "1.71.2", "version": "1.71.3",
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view", "description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -272,6 +272,17 @@ const ensureTimeZone = (dateTimeObj: any) => {
/** /**
* Create Outlook Event * Create Outlook Event
*/ */
// Normalize Outlook response dateTime: ensure UTC dates have Z suffix
const normalizeOutlookDateTime = (dtObj: any) => {
if (!dtObj?.dateTime) return dtObj;
let dt = dtObj.dateTime;
// Outlook returns UTC datetimes without Z suffix — append it
if (dt && typeof dt === 'string' && dtObj.timeZone === 'UTC' && !dt.endsWith('Z')) {
dt = dt + 'Z';
}
return { dateTime: dt, timeZone: dtObj.timeZone };
};
export const createEvent = async ( export const createEvent = async (
accessToken: string, accessToken: string,
calendarId: string, calendarId: string,
@ -281,7 +292,8 @@ export const createEvent = async (
method: 'POST', method: 'POST',
headers: { headers: {
'Authorization': `Bearer ${accessToken}`, 'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json' 'Content-Type': 'application/json',
'Prefer': 'outlook.timezone="UTC"'
}, },
body: JSON.stringify({ body: JSON.stringify({
subject: event.summary, subject: event.summary,
@ -325,8 +337,8 @@ export const createEvent = async (
id: created.id, id: created.id,
summary: created.subject, summary: created.subject,
description: created.bodyPreview, description: created.bodyPreview,
start: created.start, start: normalizeOutlookDateTime(created.start),
end: created.end, end: normalizeOutlookDateTime(created.end),
location: created.location?.displayName, location: created.location?.displayName,
allDay: created.isAllDay allDay: created.isAllDay
}; };
@ -372,9 +384,10 @@ export const updateEvent = async (
} : {}), } : {}),
}); });
const patchHeaders = { const patchHeaders: Record<string, string> = {
'Authorization': `Bearer ${accessToken}`, 'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json' 'Content-Type': 'application/json',
'Prefer': 'outlook.timezone="UTC"'
}; };
const encodedEventId = encodeURIComponent(eventId); const encodedEventId = encodeURIComponent(eventId);
@ -402,8 +415,8 @@ export const updateEvent = async (
id: updated.id, id: updated.id,
summary: updated.subject, summary: updated.subject,
description: updated.bodyPreview, description: updated.bodyPreview,
start: updated.start, start: normalizeOutlookDateTime(updated.start),
end: updated.end, end: normalizeOutlookDateTime(updated.end),
location: updated.location?.displayName, location: updated.location?.displayName,
allDay: updated.isAllDay allDay: updated.isAllDay
}; };