Changes Made

1. config/schema.sql — Added timezone_name VARCHAR(100) to user_preferences table + an ALTER TABLE migration at the bottom for existing DBs.
  2. core/tz.py — Rewrote with dual-path timezone support:
  - Request context: _get_request_tz() now checks X-Timezone-Name header (IANA) first, falls back to X-Timezone-Offset
  - Background jobs: New tz_for_user(user_uuid) and user_now_for(user_uuid) read stored timezone_name from prefs, fall back to numeric offset, then UTC
  - All existing function signatures (user_now(), user_today()) preserved for backward compat

  3. scheduler/daemon.py — Fixed 3 bugs:
  - _user_now_for() now delegates to tz.user_now_for() which uses IANA timezone names (DST-safe)
  - check_nagging() — replaced datetime.utcnow() with _user_now_for(user_uuid) so nags evaluate in user's timezone
  - poll_callback() — replaced single UTC midnight check with _check_per_user_midnight_schedules() that iterates users and creates daily schedules at their local midnight

  4. api/routes/preferences.py — Added "timezone_name" to allowed PUT fields.

  5. synculous-client/src/lib/api.ts — Added X-Timezone-Name header to every request + added timezone_name to preferences update type.

  6. synculous-client/src/app/dashboard/layout.tsx — Now syncs both timezone_offset and timezone_name (via Intl.DateTimeFormat().resolvedOptions().timeZone) on session start.
This commit is contained in:
2026-02-17 18:02:07 -06:00
parent 0e28e1ac9d
commit 80ebecf0b1
6 changed files with 124 additions and 29 deletions

View File

@@ -21,6 +21,7 @@ async function request<T>(
const headers: HeadersInit = {
'Content-Type': 'application/json',
'X-Timezone-Offset': String(new Date().getTimezoneOffset()),
'X-Timezone-Name': Intl.DateTimeFormat().resolvedOptions().timeZone,
...(token ? { Authorization: `Bearer ${token}` } : {}),
...options.headers,
};
@@ -636,6 +637,7 @@ export const api = {
show_launch_screen?: boolean;
celebration_style?: string;
timezone_offset?: number;
timezone_name?: string;
}) => {
return request<Record<string, unknown>>('/api/preferences', {
method: 'PUT',