Show reminder times in the clinic's time zone

Node · Node · intermediate · modification

Reminder texts showed appointment times in UTC, which confused patients (support tickets from the Berlin and New York clinics). This formats the date and time in the clinic's own zone with date-fns's time-zone support: `@date-fns/tz` provides the `tz()` helper and `format` takes it through the `in` option, so daylight-saving changes are handled by the library rather than by offset math. The ` UTC` suffix is dropped, since the time is now the clinic's local time.

Node 20 SMS reminder worker, CommonJS, plain JavaScript (no TypeScript build). `findDueReminders` (existing, unchanged) loads each due appointment with its clinic as `{ id, name, timeZone }` (the `clinics.time_zone` column the booking UI already uses) and calls `reminderText` once per SMS. `package-lock.json` is updated in the same commit and not shown: it resolves `date-fns` to 3.6.0 and `@date-fns/tz` to 1.5.0. `reminderText` has no tests today.

Requirements

Files touched

--- package.json
   },
   "dependencies": {
+    "@date-fns/tz": "^1.5.0",
     "date-fns": "^3.6.0",
     "pg": "^8.12.0"
--- src/reminders/message.js
 const { format } = require('date-fns');
+const { tz } = require('@date-fns/tz');
 
 // Appointment times come from a timestamptz column as Date instances.
-// The worker runs with TZ=UTC, so this formats in UTC.
-const WHEN_PATTERN = "EEE d MMM 'at' HH:mm 'UTC'";
+// Patients read them in the clinic's own time zone, DST included.
+const WHEN_PATTERN = "EEE d MMM 'at' HH:mm";
 
 function reminderText(appointment, clinic) {
-  const when = format(appointment.startsAt, WHEN_PATTERN);
+  const when = format(appointment.startsAt, WHEN_PATTERN, { in: tz(clinic.timeZone) });
   return `Reminder: your appointment at ${clinic.name} is on ${when}. Reply C to cancel.`;
 }

Review this PR

Node practice