Unix时间戳自定义加解密结果不一致问题(新加坡UTC时区)
自定义Unix时间戳加解密函数不一致问题排查与修复
问题背景
现有针对Unix时间戳的自定义加解密函数,输入参考码为const referenceCode = "1680698995321";(基于新加坡UTC+8时区),测试发现加密后解密结果与原参考码不一致:
- 加密结果:
040523-8995321 - 解密结果:
1680688995321 - 对比:
1680698995321 !== 1680688995321
原加密函数
const encryptCode = (referenceNo: string) => { const refCode = referenceNo.slice(6); const refModified = referenceNo.slice(0, 6) + "0".repeat(7); const refInt = parseInt(refModified); const date = new Date(refInt); const formattedDate = date.toLocaleDateString("fil-PH", { month: "2-digit", day: "2-digit", year: "2-digit" }).replace(/\//g, ''); return `${formattedDate}-${refCode}`; }
原解密函数
const decryptCode = (encryptedCode: string) => { const dateRef = encryptedCode.slice(0, 6); const dateCode = encryptedCode.slice(7); const dateMonth = dateRef.slice(0, 2); const dateDay = dateRef.slice(2, 4); const dateYear = dateRef.slice(4); const dateString = `${dateMonth}/${dateDay}/${dateYear} 8:00:00 UTC`; const date = new Date(dateString); const timestamp = date.getTime(); const result = timestamp.toString().slice(0, 6) + "0".repeat(7) return parseInt(result) + parseInt(dateCode); }
问题原因
核心问题是时区处理逻辑不一致:
- 加密阶段:
refModified是原时间戳前6位拼接7个0(即1680690000000),对应UTC时间2023-04-05T00:00:00Z,在菲律宾/新加坡时区(UTC+8)下本地时间为2023-04-05 08:00:00,通过toLocaleDateString("fil-PH")得到日期040523。 - 解密阶段:错误构造了UTC时间
2023-04-05T08:00:00Z(对应本地时间2023-04-05 16:00:00),生成的时间戳前6位为168072,与加密时的168069不符,最终导致结果偏差10^7毫秒。
修复方案
修改解密函数,确保时区逻辑与加密阶段一致,还原出正确的refModified时间戳。以下提供两种可靠方案:
方案一:基于UTC时间构造匹配的时间点
直接构造UTC时区的当日0点,对应本地时区(UTC+8)的8点,与加密阶段的时间点完全匹配:
const decryptCode = (encryptedCode: string) => { const dateRef = encryptedCode.slice(0, 6); const dateCode = encryptedCode.slice(7); const dateMonth = dateRef.slice(0, 2); const dateDay = dateRef.slice(2, 4); const dateYear = dateRef.slice(4); // 构造UTC时间的当月当日0点,对应本地时区8点 const dateString = `${dateMonth}/${dateDay}/${dateYear} 00:00:00 UTC`; const date = new Date(dateString); const timestamp = date.getTime(); const result = timestamp.toString().slice(0, 6) + "0".repeat(7); return parseInt(result) + parseInt(dateCode); }
方案二:直接构造本地时区时间(更可靠)
通过Date构造函数直接创建本地时区的当日8点,避免字符串解析的时区歧义:
const decryptCode = (encryptedCode: string) => { const dateRef = encryptedCode.slice(0, 6); const dateCode = encryptedCode.slice(7); const dateMonth = parseInt(dateRef.slice(0, 2)) - 1; // 月份从0开始 const dateDay = parseInt(dateRef.slice(2, 4)); const dateYear = 2000 + parseInt(dateRef.slice(4)); // 构造本地时区(UTC+8)的当月当日8点 const date = new Date(dateYear, dateMonth, dateDay, 8, 0, 0); const timestamp = date.getTime(); const result = timestamp.toString().slice(0, 6) + "0".repeat(7); return parseInt(result) + parseInt(dateCode); }
验证结果
修复后重新测试:
console.log(encryptCode(referenceCode)); // 040523-8995321 console.log(decryptCode(encryptCode(referenceCode))); // 1680698995321 referenceCode === decryptCode(encryptCode(referenceCode)) // true
内容的提问来源于stack exchange,提问作者John Joseph
相关产品推荐
相关产品推荐

