fix: show archive chart times in UTC+8 and parse Beijing wall clock

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-08 16:47:09 +08:00
parent 947b58084d
commit 55a979eee5
5 changed files with 103 additions and 32 deletions
+2 -13
View File
@@ -48,6 +48,7 @@ from hub_symbol_archive_lib import (
init_db as init_archive_db,
list_symbol_rows,
load_symbol_trades,
parse_wall_clock_ms,
resolve_archive_chart,
sync_exchange_symbol_archives,
upsert_trade_overlay,
@@ -1903,19 +1904,7 @@ def _parse_anchor_ms(at: str = "", anchor_ms: str = "") -> int | None:
raw = (anchor_ms or at or "").strip()
if not raw:
return None
if raw.isdigit():
v = int(raw)
return v if v > 1_000_000_000_000 else v * 1000
s = raw.replace("Z", "").replace("T", " ")
for fmt, ln in (("%Y-%m-%d %H:%M:%S", 19), ("%Y-%m-%d %H:%M", 16), ("%Y-%m-%d", 10)):
try:
from datetime import datetime
dt = datetime.strptime(s[:ln], fmt)
return int(dt.timestamp() * 1000)
except ValueError:
continue
return None
return parse_wall_clock_ms(raw)
@app.get("/api/archive/meta")
+65 -9
View File
@@ -33,6 +33,7 @@
"1h": 60 * 60_000,
"4h": 4 * 60 * 60_000,
};
const CHART_TZ_OFFSET_SEC = 8 * 60 * 60;
let meta = null;
let listRows = [];
@@ -92,6 +93,59 @@
return s;
}
function pad2(n) {
return n < 10 ? "0" + n : String(n);
}
function utcSecToBjDate(utcSec) {
return new Date((Number(utcSec) + CHART_TZ_OFFSET_SEC) * 1000);
}
function formatChartTimeBj(utcSec, withDate) {
const d = utcSecToBjDate(utcSec);
const h = pad2(d.getUTCHours());
const mi = pad2(d.getUTCMinutes());
if (!withDate) return h + ":" + mi;
return (
d.getUTCFullYear() +
"-" +
pad2(d.getUTCMonth() + 1) +
"-" +
pad2(d.getUTCDate()) +
" " +
h +
":" +
mi
);
}
function chartLocalizationBj() {
return {
locale: "zh-CN",
dateFormat: "yyyy-MM-dd",
timeFormatter: function (time) {
if (typeof time === "number") return formatChartTimeBj(time, true);
if (time && typeof time === "object" && time.year) {
return time.year + "-" + pad2(time.month) + "-" + pad2(time.day);
}
return "";
},
tickMarkFormatter: function (time, tickMarkType) {
if (typeof time !== "number") {
if (time && typeof time === "object" && time.year) {
return time.year + "-" + pad2(time.month) + "-" + pad2(time.day);
}
return "";
}
const d = utcSecToBjDate(time);
if (tickMarkType === 0) return String(d.getUTCFullYear());
if (tickMarkType === 1) return pad2(d.getUTCMonth() + 1);
if (tickMarkType === 2) return pad2(d.getUTCDate());
return formatChartTimeBj(time, false);
},
};
}
function fmtDt(raw) {
if (raw == null || raw === "") return "—";
return String(raw).replace("T", " ").slice(0, 16);
@@ -246,15 +300,16 @@
if (!s) return null;
const m = s.match(/^(\d{4})-(\d{2})-(\d{2})(?: (\d{2}):(\d{2})(?::(\d{2}))?)?/);
if (!m) return null;
const dt = new Date(
Number(m[1]),
Number(m[2]) - 1,
Number(m[3]),
Number(m[4] || 0),
Number(m[5] || 0),
Number(m[6] || 0)
);
const ms = dt.getTime();
const ms =
Date.UTC(
Number(m[1]),
Number(m[2]) - 1,
Number(m[3]),
Number(m[4] || 0),
Number(m[5] || 0),
Number(m[6] || 0)
) -
CHART_TZ_OFFSET_SEC * 1000;
return Number.isFinite(ms) ? ms : null;
}
@@ -447,6 +502,7 @@
horzLines: { color: isDark ? "#1a2030" : "#e8ecf2" },
},
rightPriceScale: { borderColor: isDark ? "#2a3348" : "#d0d7e2", autoScale: true },
localization: chartLocalizationBj(),
timeScale: {
borderColor: isDark ? "#2a3348" : "#d0d7e2",
timeVisible: true,
+1 -1
View File
@@ -418,7 +418,7 @@
<script src="https://unpkg.com/lightweight-charts@4.2.0/dist/lightweight-charts.standalone.production.js"></script>
<script src="/assets/chart_draw.js?v=20260608-market-vol-rank"></script>
<script src="/assets/chart.js?v=20260608-market-vol-rank-v5"></script>
<script src="/assets/archive.js?v=20260607-hub-archive-v6"></script>
<script src="/assets/archive.js?v=20260608-hub-archive-tz8"></script>
<script src="/assets/ai_review_render.js?v=2"></script>
<script src="/assets/app.js?v=20260607-hub-archive-v1"></script>
</body>