概述
JS 中使用 Date 类型记录时间。Date 类型是对时间的抽象封装,它提供了许多操作时间的便利方法。本文整理了如何使用 Date 来处理时间,以及解决时区转换带来的问题。
Date 实例
一个 Date 实例封装了一个时间,其中,时间的底层表示方式是1970年1月1日至今的毫秒数。并且,这里毫秒数的计算与时区无关,均以 UTC±0 计算。在同一时刻生成的 Date 实例,无论是在北京,还是在西雅图,其中封装的时间都是相同的。
时间的传输与显示
在实际环境中,时间信息经常需要在不同的系统之间传输。最简单的方法便是采用时间的毫秒数表达方式。这种方式不需要考虑时区问题,能够准确传递时间信息,并且,由于使用的是整数数据类型,适用于所有的系统。JS Date 实例的 getTime()、valueOf() 接口可以返回1970年1月1日至今的毫秒数。
时间的毫秒数表达方式对机器友好,但是不易理解。当时间从毫秒数转换为人类可以理解的时间表达方式时,需要考虑时区的影响。
JS 中 Date 实例提供的接口包含本地化(时区有关)接口和时区无关接口。比如,Date 实例的 toString() 接口返回的是本地化的时间,getUTCHours() 接口返回的是时区无关的信息。
案例分析
存在一个 BS(Browser-Server)结构的系统,用户在浏览器上执行了某项操作,这个操作的时间会发送至服务端存储。浏览器与服务端均可能处于任意时区。如果使用1970年1月1日至今的毫秒数来表示和传递时间,不需要考虑时区问题。
对于希望以北京时间(UTC+8)、人类可理解的方式来表示时间时,有如下两种处理方式。
1、如果当前执行环境所在的时区为 UTC+8,那么直接使用 Date 实例的本地化接口就能获得北京时间的表达。Date 实例的 getTimezoneOffset() 接口可以判断当前所处的时区,其返回值表示本地时区与 UTC±0 时区分钟差。
1 | /* 本地化接口 */ |
2、如果不想考虑当前执行环境所在时区带来的影响,Date 也提供了一系列时区无关的接口。如下代码所示,核心思想是将原始时间和转换后的时间都当成 UTC±0 的时间来处理。
1 | function getFormattedBeijingDateString(timestamp) { |
moment.js
moment().utcOffset(8).format('YYYY-MM-DD');
使用这种方法可以显示北京时间。
moment.js 的 utcOffset() 接口的核心逻辑如下语句所示,其原理和上一小节时区无关的处理方式类似。
mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);