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:
@@ -130,16 +130,23 @@ def collect(since=None, until=None) -> list[dict]:
|
||||
return out
|
||||
|
||||
|
||||
def _tz():
|
||||
from zoneinfo import ZoneInfo
|
||||
return ZoneInfo(config.DISPLAY_TZ)
|
||||
|
||||
|
||||
def month_bounds(month: str):
|
||||
"""'2026-10' -> (2026-10-01T00:00Z, 2026-11-01T00:00Z)."""
|
||||
"""'2026-10' -> start of that month and of the next, in the site's
|
||||
display timezone (a wipe at 21:00 EDT on the 31st belongs to that
|
||||
month, not the next one as it would in UTC)."""
|
||||
y, m = (int(x) for x in month.split("-"))
|
||||
start = datetime(y, m, 1, tzinfo=timezone.utc)
|
||||
end = datetime(y + (m == 12), m % 12 + 1, 1, tzinfo=timezone.utc)
|
||||
start = datetime(y, m, 1, tzinfo=_tz())
|
||||
end = datetime(y + (m == 12), m % 12 + 1, 1, tzinfo=_tz())
|
||||
return start, end
|
||||
|
||||
|
||||
def previous_month(now=None) -> str:
|
||||
now = now or datetime.now(timezone.utc)
|
||||
now = now or datetime.now(_tz())
|
||||
y, m = (now.year, now.month - 1) if now.month > 1 else (now.year - 1, 12)
|
||||
return f"{y:04d}-{m:02d}"
|
||||
|
||||
@@ -150,7 +157,7 @@ def summary_csv(reports: list[dict], state: dict) -> str:
|
||||
writer.writeheader()
|
||||
for r in reports:
|
||||
writer.writerows(blancco_report.export_rows(
|
||||
r["file"], r["data"], r["when"].isoformat(),
|
||||
r["file"], r["data"], r["when"].astimezone(_tz()).isoformat(),
|
||||
cloud_status(state, r["document_id"])))
|
||||
return buf.getvalue()
|
||||
|
||||
@@ -168,7 +175,7 @@ def build_evidence_zip(month: str, fileobj) -> int:
|
||||
with zipfile.ZipFile(fileobj, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||
zf.writestr(f"{stem}/summary.csv", summary_csv(reports, state))
|
||||
zf.writestr(f"{stem}/README.txt", (
|
||||
f"Blancco erasure evidence, {config.BLANCCO_SITE}, {month} (UTC)\n"
|
||||
f"Blancco erasure evidence, {config.BLANCCO_SITE}, {month} ({config.DISPLAY_TZ})\n"
|
||||
f"{len(reports)} report(s). summary.csv has one row per erased drive,\n"
|
||||
"with failure_reason for failed wipes and cloud_upload as recorded by\n"
|
||||
"the PXE server. Certificates of record are in the Blancco Management\n"
|
||||
@@ -206,7 +213,7 @@ def servicenow_items(days: int = 30, include_done: bool = False) -> list[dict]:
|
||||
items.append({
|
||||
"document_id": r["document_id"],
|
||||
"file": r["file"],
|
||||
"when": r["when"],
|
||||
"when": r["when"].astimezone(_tz()),
|
||||
"serial": system.get("serial", ""),
|
||||
"model": system.get("model", ""),
|
||||
"failed": bool(failed) or not erasures,
|
||||
|
||||
Reference in New Issue
Block a user