前端getTime时区问题

3,519 阅读2分钟

问题

  发现客户端选择下单时间后,提交订单并查看订单,在订单上显示的之前用户之前选择的时间存在1-N小时不等的差值。
  例如:在下单页选择的2018-01-01 10:00,下单完成后,在订单详情页上面显示为2018-01-01 09:00,与实际的相差1小时。

分析

  结合代码分析,发现当用户选择完时间后,会把选择的时间字符串调用getTime方法转换为毫秒数传给后端,后端再转换回时间字符串,在这个转换过程中,时间出现了差值。
  最终,排查出问题原因为时区问题。还是以上面的样例为范本。当客户端的时区为东京,服务器端的时区为北京就能完美复该问题。
  使用getTime方法获取时间的毫秒数时,实际上的获取当前的格林威治时间1970年1月1日之间的毫秒数。东京时间为东9区,比标准时间快9个小时,所以在东京时区下时间转毫秒数就会减去9个小时才会为标准时间。此时北京时间与标准时间为8个小时的时差,客户端用东京时间转换为毫秒数(减9个小时),服务器端再用北京时间把毫秒数转换为时间字符串(加8个小时),此时就出现了时间差。

解决

  1. 避免使用getTime,前后端直接使用时间字符串传输
  2. 前端对时区就行修复,代码如下
function getTruthTime (time) {
  // 服务器端时区,北京东八区(-8*60)
  let timezone = -480
  // 客户端实际时区(例如东京为东九区:-540)
  let offsetGMT = new Date().getTimezoneOffset()
  // 计算差值(用户在东京时区下下单,需要补回1小时)
  let adjust = timezone - offsetGMT
  // 需要修复的时间,支持字符串传参
  let nowDate = time ? new Date(time).getTime() : new Date().getTime()
  let timeStamp = new Date(nowDate + adjust * 60 * 1000)
  return timeStamp.getTime()
}