fix(db): 日志与忽略记录时间统一为北京时间(东八区墙上时间)

- SQLite DEFAULT CURRENT_TIMESTAMP 为 UTC,与前端展示差 8 小时
- 新增 nowIso() 显式写入东八区墙上时间(YYYY-MM-DD HH:MM:SS)
- 旧数据迁移 v1:日志/忽略记录 UTC 时间统一转北京时间,settings 标志位防重复执行
- 已用临时库验证迁移、幂等与新写入格式
This commit is contained in:
yinjun.chen1
2026-09-21 09:56:11 +08:00
parent 115c5ccc9a
commit 794d204491
+47 -4
View File
@@ -35,12 +35,52 @@ CREATE TABLE IF NOT EXISTS logs (
);
`)
// 北京时间(Asia/Shanghai 固定 UTC+8,无夏令时):SQLite DEFAULT CURRENT_TIMESTAMP 是 UTC,
// 与前端按本地时间展示相差 8 小时,故写入与迁移统一显式使用北京时间墙上时间字符串
// (格式与前端 slice 兼容:YYYY-MM-DD HH:MM:SS,不带时区后缀,避免被二次误解)
const pad2 = n => String(n).padStart(2, '0')
export function nowIso() {
const d = new Date(Date.now() + 8 * 3600_000)
return `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())} ${pad2(d.getUTCHours())}:${pad2(d.getUTCMinutes())}:${pad2(d.getUTCSeconds())}`
}
function utcToShanghai(iso) {
try {
const ts = Date.parse(iso)
if (!Number.isFinite(ts)) return null
const d = new Date(ts + 8 * 3600_000)
return `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())} ${pad2(d.getUTCHours())}:${pad2(d.getUTCMinutes())}:${pad2(d.getUTCSeconds())}`
} catch {
return null
}
}
// 旧库迁移:早期 logs 表无 action 列,运行时补齐(忽略/取消忽略等操作依赖该列区分类型)
const logCols = db.prepare('PRAGMA table_info(logs)').all().map(c => c.name)
if (!logCols.includes('action')) {
db.exec("ALTER TABLE logs ADD COLUMN action TEXT DEFAULT 'clean'")
}
// 旧库迁移 v1:历史日志/忽略记录的时间戳是 UTC,统一转成北京时间;settings 标志位防重复执行
function migrateTimezone() {
if (getSetting('timezone_migrated_v1')) return
db.transaction(() => {
for (const { id, created_at: t } of db.prepare('SELECT id, created_at FROM logs').all()) {
if (t) {
const local = utcToShanghai(t)
if (local) db.prepare('UPDATE logs SET created_at = ? WHERE id = ?').run(local, id)
}
}
for (const { pkg_name: n, ignored_at: t } of db.prepare('SELECT pkg_name, ignored_at FROM ignored_packages').all()) {
if (t) {
const local = utcToShanghai(t)
if (local) db.prepare('UPDATE ignored_packages SET ignored_at = ? WHERE pkg_name = ?').run(local, n)
}
}
setSetting('timezone_migrated_v1', '1')
})()
}
// —— settings ——
export function getSetting(key, def = null) {
const row = db.prepare('SELECT value FROM settings WHERE key = ?').get(key)
@@ -68,8 +108,8 @@ export function isIgnored(pkgName) {
export function addIgnored(pkgName) {
db.prepare(
'INSERT INTO ignored_packages (pkg_name) VALUES (?) ON CONFLICT(pkg_name) DO NOTHING',
).run(pkgName)
'INSERT INTO ignored_packages (pkg_name, ignored_at) VALUES (?, ?) ON CONFLICT(pkg_name) DO NOTHING',
).run(pkgName, nowIso())
}
export function removeIgnored(pkgName) {
@@ -79,8 +119,8 @@ export function removeIgnored(pkgName) {
// —— logs ——
export function addLog({ action = 'clean', pkgName, deletedVersions = null, deletedCount = 0, freedSpace = null }) {
const info = db.prepare(
'INSERT INTO logs (action, pkg_name, deleted_versions, deleted_count, freed_space) VALUES (?, ?, ?, ?, ?)',
).run(action, pkgName, deletedVersions, deletedCount, freedSpace)
'INSERT INTO logs (action, pkg_name, deleted_versions, deleted_count, freed_space, created_at) VALUES (?, ?, ?, ?, ?, ?)',
).run(action, pkgName, deletedVersions, deletedCount, freedSpace, nowIso())
return info.lastInsertRowid
}
@@ -90,4 +130,7 @@ export function getLogs(limit = 50) {
).all(limit)
}
// 模块加载时执行时间迁移(幂等)
migrateTimezone()
export default db