diff --git a/backend/open_webui/models/automations.py b/backend/open_webui/models/automations.py index c891c3204..02a6f231d 100644 --- a/backend/open_webui/models/automations.py +++ b/backend/open_webui/models/automations.py @@ -273,9 +273,20 @@ class AutomationTable: from open_webui.utils.automations import next_run_ns + # Batch-fetch user timezones so rescheduling respects each + # user's local timezone instead of falling back to server time. + user_ids = list({row.user_id for row in rows}) + timezone_by_user_id: dict[str, Optional[str]] = {} + if user_ids: + from open_webui.models.users import User + tz_result = await db.execute( + select(User.id, User.timezone).where(User.id.in_(user_ids)) + ) + timezone_by_user_id = {uid: tz for uid, tz in tz_result.all()} + for row in rows: row.last_run_at = now_ns - row.next_run_at = next_run_ns(row.data.get('rrule', '')) + row.next_run_at = next_run_ns(row.data.get('rrule', ''), tz=timezone_by_user_id.get(row.user_id)) await db.commit() diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 8aeda1659..f62aa20ca 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -51,7 +51,7 @@ import 'tippy.js/dist/tippy.css'; import { executeToolServer, getBackendConfig, getModels, getVersion } from '$lib/apis'; - import { getSessionUser, userSignOut } from '$lib/apis/auths'; + import { getSessionUser, updateUserTimezone, userSignOut } from '$lib/apis/auths'; import { getAllTags, getChatList } from '$lib/apis/chats'; import { chatCompletion } from '$lib/apis/openai'; import { @@ -62,7 +62,7 @@ } from '$lib/utils/connections'; import { WEBUI_API_BASE_URL, WEBUI_BASE_URL, WEBUI_HOSTNAME } from '$lib/constants'; - import { bestMatchingLanguage, displayFileHandler } from '$lib/utils'; + import { bestMatchingLanguage, displayFileHandler, getUserTimezone } from '$lib/utils'; import { setTextScale } from '$lib/utils/text-scale'; import NotificationToast from '$lib/components/NotificationToast.svelte'; @@ -989,6 +989,12 @@ console.error('Error refreshing backend config:', error); } + // Keep user timezone in sync on every app load/refresh + const timezone = getUserTimezone(); + if (timezone) { + updateUserTimezone(localStorage.token, timezone); + } + // Relay auth token to desktop app for API access if (window.electronAPI?.send) { window.electronAPI