fix(frontend): parse local expiry datetimes strictly

This commit is contained in:
lylelllll
2026-08-30 23:19:45 +08:00
committed by GitHub
parent b7aca87fd0
commit 81e461f651
+57 -3
View File
@@ -201,9 +201,63 @@ export function formatDateTimeLocalInput(timestampSeconds: number | null): strin
*/
export function parseDateTimeLocalInput(value: string): number | null {
if (!value) return null
const date = new Date(value)
if (isNaN(date.getTime())) return null
return Math.floor(date.getTime() / 1000)
// datetime-local intentionally has no timezone. Parse its components explicitly
// so malformed values or timezone-bearing strings are not reinterpreted by Date.parse.
const match = /^(\d{4,})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?$/.exec(value)
if (!match) return null
const year = Number(match[1])
const month = Number(match[2])
const day = Number(match[3])
const hours = Number(match[4])
const minutes = Number(match[5])
const seconds = match[6] ? Number(match[6]) : 0
const milliseconds = match[7]
? Number(match[7].slice(0, 3).padEnd(3, '0'))
: 0
if (
!Number.isSafeInteger(year) ||
year < 1 ||
month < 1 ||
month > 12 ||
day < 1 ||
day > 31 ||
hours > 23 ||
minutes > 59 ||
seconds > 59
) {
return null
}
const date = new Date(0)
date.setFullYear(year, month - 1, day)
date.setHours(hours, minutes, seconds, milliseconds)
// Date setters normalize calendar overflows (for example, February 30). Keep
// the platform's existing DST disambiguation for otherwise valid local times.
if (
date.getFullYear() !== year ||
date.getMonth() !== month - 1 ||
date.getDate() !== day
) {
return null
}
const timestamp = date.getTime()
return Number.isFinite(timestamp) ? Math.floor(timestamp / 1000) : null
}
/**
* 获取浏览器当前使用的 IANA 时区
*/
export function getBrowserTimeZone(): string {
try {
return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'
} catch {
return 'UTC'
}
}
/**