mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-10-28 11:14:58 +00:00
migrate stored TZ formats from IANA labels on boot
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate src/ESP32React/tz_zones.h from interface/src/app/settings/TZ.tsx.
|
||||
|
||||
Run from the repo root:
|
||||
python3 scripts/generate_tz_zones.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
TZ_TSX = ROOT / "interface" / "src" / "app" / "settings" / "TZ.tsx"
|
||||
OUT_H = ROOT / "src" / "ESP32React" / "tz_zones.h"
|
||||
|
||||
|
||||
def parse_time_zones(text: str) -> list[tuple[str, str]]:
|
||||
match = re.search(
|
||||
r"export const TIME_ZONES: Record<string, string> = \{([\s\S]*?)\n\};",
|
||||
text,
|
||||
)
|
||||
if not match:
|
||||
raise SystemExit("TIME_ZONES table not found in TZ.tsx")
|
||||
entries = re.findall(r"'((?:\\'|[^'])*)': '((?:\\'|[^'])*)'", match.group(1))
|
||||
if not entries:
|
||||
raise SystemExit("no TIME_ZONES entries parsed")
|
||||
return sorted(entries, key=lambda item: item[0])
|
||||
|
||||
|
||||
def c_string(value: str) -> str:
|
||||
return '"' + value.replace("\\", "\\\\").replace('"', '\\"') + '"'
|
||||
|
||||
|
||||
def main() -> int:
|
||||
entries = parse_time_zones(TZ_TSX.read_text(encoding="utf-8"))
|
||||
max_format = max(len(fmt) for _, fmt in entries)
|
||||
|
||||
lines = [
|
||||
"/* Auto-generated by scripts/generate_tz_zones.py — do not edit. */",
|
||||
"#pragma once",
|
||||
"",
|
||||
"#include <stdlib.h>",
|
||||
"#include <string.h>",
|
||||
"",
|
||||
"struct EmsespTzZone {",
|
||||
" const char * label;",
|
||||
" const char * format;",
|
||||
"};",
|
||||
"",
|
||||
f"// Longest POSIX TZ value in the table is {max_format} chars.",
|
||||
"static constexpr size_t EMSESP_TZ_ZONE_COUNT = "
|
||||
f"{len(entries)};",
|
||||
"static const EmsespTzZone EMSESP_TZ_ZONES[EMSESP_TZ_ZONE_COUNT] = {",
|
||||
]
|
||||
for label, fmt in entries:
|
||||
lines.append(f" {{{c_string(label)}, {c_string(fmt)}}},")
|
||||
lines += [
|
||||
"};",
|
||||
"",
|
||||
"inline int emsesp_tz_zone_cmp(const void * key, const void * element) {",
|
||||
" return strcmp(static_cast<const char *>(key), static_cast<const EmsespTzZone *>(element)->label);",
|
||||
"}",
|
||||
"",
|
||||
"// Returns the POSIX TZ string for an IANA label, or nullptr if unknown.",
|
||||
"inline const char * emsesp_tz_format_for_label(const char * label) {",
|
||||
" if (label == nullptr || *label == '\\0') {",
|
||||
" return nullptr;",
|
||||
" }",
|
||||
" const auto * found = static_cast<const EmsespTzZone *>(",
|
||||
" bsearch(label, EMSESP_TZ_ZONES, EMSESP_TZ_ZONE_COUNT, sizeof(EmsespTzZone), emsesp_tz_zone_cmp));",
|
||||
" return found != nullptr ? found->format : nullptr;",
|
||||
"}",
|
||||
"",
|
||||
]
|
||||
OUT_H.write_text("\n".join(lines), encoding="utf-8")
|
||||
print(f"Wrote {OUT_H.relative_to(ROOT)} ({len(entries)} zones, max format {max_format})")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user