fix(db): 日志与忽略记录时间统一为北京时间(东八区墙上时间)
- SQLite DEFAULT CURRENT_TIMESTAMP 为 UTC,与前端展示差 8 小时 - 新增 nowIso() 显式写入东八区墙上时间(YYYY-MM-DD HH:MM:SS) - 旧数据迁移 v1:日志/忽略记录 UTC 时间统一转北京时间,settings 标志位防重复执行 - 已用临时库验证迁移、幂等与新写入格式
This commit is contained in:
+47
-4
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user