如何将用户选定时区下的datetime正确转换为UTC时间
问题根因
你当前的写法逻辑存在偏差:Date.prototype.toLocaleString 传入 timeZone 参数的作用是将现有Date实例对应的时间转换为目标时区的显示字符串,你后续把这个字符串传给new Date()时,浏览器会默认按设备本地时区(也就是你例子里的Asia/Karachi)解析该字符串,自然得不到预期结果。
另外你的示例计算存在笔误:Europe/Prague在9月处于夏令时,UTC偏移为+2,选定的15:30减2小时后对应的UTC时间应为13:30,而非13:20。
原生JS实现方案
无需引入第三方依赖的实现逻辑如下:
/** * 将指定时区的用户选定时间转换为UTC时间 * @param {string} userDatetimeStr 日期选择器输出的ISO格式时间,示例:'2021-09-14T15:30:00' * @param {string} targetTimezone 用户选定的时区标识,示例:'Europe/Prague' * @returns {Date} 转换后的UTC时间对象 */ function convertTzDatetimeToUTC(userDatetimeStr, targetTimezone) { // 拆分用户输入的时间部件 const [datePart, timePart] = userDatetimeStr.split('T'); const [year, month, day] = datePart.split('-').map(Number); const [hour, minute] = timePart.split(':').map(Number); const userInputTs = Date.UTC(year, month - 1, day, hour, minute); // 构造目标时区的时间格式化器 const tzFormatter = new Intl.DateTimeFormat('en-US', { timeZone: targetTimezone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false }); // 计算时区偏移量 const tempDate = new Date(userInputTs); const parts = Object.fromEntries(tzFormatter.formatToParts(tempDate).map(item => [item.type, item.value])); const tzTimeTs = Date.UTC( Number(parts.year), Number(parts.month) - 1, Number(parts.day), Number(parts.hour), Number(parts.minute) ); const offsetMs = userInputTs - tzTimeTs; // 返回UTC时间 return new Date(userInputTs - offsetMs); } // 调用示例 const resultUtcDate = convertTzDatetimeToUTC('2021-09-14T15:30:00', 'Europe/Prague'); // 输出结果为 2021-09-14T13:30:00.000Z,符合预期
第三方库简化方案
如果项目允许引入工具库,使用Day.js的时区插件可以大幅简化逻辑:
import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; import timezone from 'dayjs/plugin/timezone'; dayjs.extend(utc); dayjs.extend(timezone); // 直接按指定时区构造时间再转UTC const resultUtcDate = dayjs.tz('2021-09-14 15:30:00', 'Europe/Prague').utc().toDate();
内容的提问来源于stack exchange,提问作者Azher Aleem
相关产品推荐
相关产品推荐

