Show every time in US Eastern (America/New_York)

Webapp: config.DISPLAY_TZ (default America/New_York) and a local_dt
filter that renders datetimes, ISO strings and Unix timestamps as e.g.
"2026-10-05 13:54 EDT", DST included. Used for the ServiceNow tick list,
technician to-do, imaging tiles and detail page; timestamp_fmt (reports,
backups, enrollment) goes through it too instead of relying on the
process TZ. CSV report_date is Eastern with its offset. Evidence-pack
months are Eastern calendar months, so a wipe late on the 31st lands in
that month rather than the next.

Blancco: init points the new root's /etc/localtime at America/New_York
so the GUI clock is local. Report timestamps keep their explicit
offset; report.utc_offset stays 0 since a fixed offset cannot follow DST.
Report file names stay UTC, as Blancco's own Save names them.
This commit is contained in:
cproudlock
2026-10-05 14:16:14 -04:00
parent 121577f090
commit 83ba4865e8
8 changed files with 69 additions and 22 deletions

View File

@@ -638,7 +638,7 @@ def blancco_export_reports():
if when < since:
continue
rows.extend(blancco_report.export_rows(
f, data, when.isoformat(),
f, data, to_display_tz(when).isoformat(),
blancco_evidence.cloud_status(cloud_state, (data.get("meta") or {}).get("document_id", ""))))
files.append(f)
pdf = os.path.splitext(f)[0] + ".pdf"
@@ -1490,10 +1490,40 @@ def api_save_unattend(image_type):
# Template helpers
# ---------------------------------------------------------------------------
def to_display_tz(value):
"""datetime (naive = UTC), ISO-8601 string or Unix timestamp -> aware
datetime in config.DISPLAY_TZ; None when it cannot be read."""
from datetime import timezone
from zoneinfo import ZoneInfo
if value is None or value == "":
return None
if isinstance(value, (int, float)):
dt = datetime.fromtimestamp(value, timezone.utc)
elif isinstance(value, datetime):
dt = value if value.tzinfo else value.replace(tzinfo=timezone.utc)
else:
try:
dt = datetime.fromisoformat(str(value).replace("Z", "+00:00"))
except ValueError:
return None
if not dt.tzinfo:
dt = dt.replace(tzinfo=timezone.utc)
return dt.astimezone(ZoneInfo(config.DISPLAY_TZ))
@app.template_filter("local_dt")
def local_dt(value, seconds=False):
"""Any timestamp shown in the UI, as e.g. '2026-10-05 13:54 EDT'."""
dt = to_display_tz(value)
if dt is None:
return value or "-"
return dt.strftime("%Y-%m-%d %H:%M:%S %Z" if seconds else "%Y-%m-%d %H:%M %Z")
@app.template_filter("timestamp_fmt")
def timestamp_fmt(ts):
"""Format a Unix timestamp to a human-readable date string."""
return datetime.fromtimestamp(ts).strftime("%Y-%m-%d %H:%M")
"""Format a Unix timestamp in the display timezone."""
return local_dt(ts)
@app.context_processor