react项目中时区功能的实现

1,139 阅读4分钟

提要

公司售出的温湿度设备,出售到国外,因此云平台需要进行适配,此次添加了中英文切换功能以及时区切换功能。本次主要记录总结一下时区功能的实现。

需求

平台需要提供一个时区切换的功能,用于用户进行时区的切换,切换时区后对实时页面显示的设备的实时数据时间点进行转换。

背景

  1. 目前服务端存储的是东八区时间,通过接口、websocket返回到前端的是字符串例:2024-06-04 21:47:00

功能实现

了解了我们要实现的需求,以及当前已有的条件,接下来我们讲解怎样通过代码将其进行实现。

基础

时区、时间戳概念

首先我们先了解一下时区相关的概念,便于实现需求以及理解后续的代码逻辑。

  1. 时区:整个地区分为二十四时区,每个时区都有自己的本地时间,本地时间 = UTC + 时区差,时区差东为正,西为负。中国以北京时间为准即东八区:UTC + 8。
  2. 时间戳:时间戳是一个绝对值,代表格林威治时间(1970年01月01日00时00分00秒)到现在的总毫秒数,跟时区没有任何关系,即你在地区任何一个地方都是这个值。(服务器中存储时间戳,会避免一些问题)

js中Date 对象的局限

JS 中 Date 对象是没办法指定时区的,默认就是以用户电脑上所处的时区为基础的,当将系统中的时间分区进行调整后,获取的时间对象也会发生改变。 本地时间 image.png 切换时区为 =》(UTC-05:00) 波哥大,利马,基多,里奥布朗库 image.png

代码逻辑的实现

讲了这么多关于时区的知识,但是在我们实际实现功能的过程中是不需要一步一步的来进行实现的,可以采用现有的插件进行,本次我采用的是 moment 进行实现,通过用户切换不同的时区,来进行小时的加减。

/**
 * 处理当前的 ws 转换为 指定时区的时间
 * 服务端默认传过来的 是 UTC+8 的时间字符串
 * @param {string} timeString  2024-06-03 10:47:45
 * @param {string} nowTimeZone  后端存储的是 东八区时间 8
 * @returns 
 */
function timeZoneConver(timeString, nowTimeZone = 8) {
  let localTimeZone = Number(localStorage.getItem('timeZone') || '8');
  if (localTimeZone === 8) return timeString;
  let poorHour = localTimeZone - nowTimeZone;
  let time = null;
  if (poorHour > 0) {
    // 当前时间 + poorHour 小时后
    time = moment(timeString).add(poorHour, 'hour').format('YYYY-MM-DD HH:mm:ss');
  } else {
    // 当前时间 - poorHour 小时前
    poorHour = Math.abs(poorHour);
    time = moment(timeString).subtract(poorHour, 'hour').format('YYYY-MM-DD HH:mm:ss');
  }
  return time;
}

优化

在我们实现基础的需求上,我们做一下小小的优化:获取用户本机的时区,当用户没有选择时区的时候,以本机时区为主;当用户进行切换了时区,以本地存储的时区为主。
当然后来我们采用了接口存储在后端数据库有关用户信息的表中,以数据库中的返回的时区为主。主要是为了防止本地存储,当用户换电脑或者清除缓存后,还需要重新进行调整。

获取本机时区

/**
 * 获取 本地系统时区
 */
function getSystemTimeZone() {
  let systemTimeZone = -(new Date().getTimezoneOffset() / 60);
  return systemTimeZone;
}

将本地时间转换为平台中选择的时区

/**
 * 获取当前电脑系统时间的时区
 * 并将其转换为 当前用户选择的时区时间
 * 获取其时间戳
 */
function getSystemTimeZoneTimestamp() {
  let systemTimeZone = getSystemTimeZone();
  let nowTime = moment().format('YYYY-MM-DD HH:mm:ss');
  let converTime = timeZoneConver(nowTime, systemTimeZone);
  let converTimestamp = new Date(converTime).getTime();
  return converTimestamp;
}

在实际使用的过程中,我们直接调用 getSystemTimeZoneTimestamp 函数方法即可。

总结

说了这么多,现在回头看起来真正我们去实现的话还是很简单的,我们通过已有的一些插件取得了我们最终想要的结果,使我们避免了天、月、年这些加减,避免了对一些特殊情况的处理。
当然,目前这种情况我认为还有一些问题:

  1. 就是有一些国家或者地区是存在夏令时的,采用当前的这种方式去计算的话是不是在后续还会出现一些意外情况

毕竟我对时区这一块的基础知识、使用场景以及一些局限性还是不够了解,各位如果对此有一些观点或者方法的话,欢迎在评论区给予我一些指导,在此先进行感谢。
针对技术的探索以及应用之路是漫长与枯燥的,在此希望与各位同行,与君共勉!!!