diff --git a/plugins/backups/api/routes.py b/plugins/backups/api/routes.py
index dba92ad..6eb54cd 100644
--- a/plugins/backups/api/routes.py
+++ b/plugins/backups/api/routes.py
@@ -12,6 +12,9 @@ because requiring the app server to mount the SFLD share would turn a
permissions slip into an unexplained empty download.
"""
+from datetime import timezone
+from zoneinfo import ZoneInfo
+
from flask import Blueprint, current_app, request, Response
from flask_jwt_extended import jwt_required
@@ -22,15 +25,42 @@ from shopdb.api import (
)
from ..models import BackupRevision
+from ..models.backup import _utciso
from ..services.registry import REGISTRY, getkind
backups_bp = Blueprint('backups', __name__)
+_DEFAULTTZ = 'America/New_York'
+
+
+def _sitezone():
+ """Site-configured IANA zone (settings key site_timezone).
+
+ Same lookup the notifications plugin uses. A stored timestamp is UTC, so
+ anything rendered server-side has to be converted or it shows the wrong
+ wall clock for the site - four hours out at West Jefferson.
+ """
+ from shopdb.api import Setting
+ row = Setting.query.filter_by(key='site_timezone').first()
+ name = row.value if row and row.value else _DEFAULTTZ
+ try:
+ return ZoneInfo(name)
+ except Exception:
+ return ZoneInfo(_DEFAULTTZ)
+
+
def _label(revision):
- """Panel list title: kind-agnostic, readable at a glance."""
+ """Panel list title: kind-agnostic, readable at a glance.
+
+ Rendered in the SITE zone, not UTC: this string is baked server-side and
+ the client cannot correct it afterwards.
+ """
when = revision.collectedat or revision.createdat
- stamp = when.strftime('%Y-%m-%d %H:%M') if when else 'unknown time'
+ if not when:
+ return 'unknown time'
+ local = when.replace(tzinfo=timezone.utc).astimezone(_sitezone())
+ stamp = local.strftime('%Y-%m-%d %H:%M')
if revision.sourcefilename:
return '{} - {}'.format(stamp, revision.sourcefilename)
return stamp
@@ -129,8 +159,7 @@ def asset_info(assetid):
revision.payload, assetid,
partmarkertypes=current_app.config.get('BACKUPS_PARTMARKER_TYPES'))
data['backuprevisionid'] = revision.backuprevisionid
- data['collectedat'] = (revision.collectedat.isoformat()
- if revision.collectedat else None)
+ data['collectedat'] = _utciso(revision.collectedat)
return success_response(data)
diff --git a/plugins/backups/frontend/views/BackupHistory.vue b/plugins/backups/frontend/views/BackupHistory.vue
index b2286e9..625e689 100644
--- a/plugins/backups/frontend/views/BackupHistory.vue
+++ b/plugins/backups/frontend/views/BackupHistory.vue
@@ -95,7 +95,8 @@