以前一直都是开发国内业务,还真没遇到要处理时区的场景,shopee这边则不同,一个管理后台会按国家维度来做数据划分,最终也会交给不同国家的运营人员来维护,那么比如对于一个定时任务,则各地的运营人员需要清晰的知道该任务生效的时间(当地时间),其实概念有点绕的,作为开发人员,你面对的是你所在的时区里的时间,但你要站在对方的时区去思考这个问题,创建定时任务时,用户在datepicker里所选择的时间其实是他期望的当地时间,但momentjs默认会以你系统的时区来处理时间,所以,你如果直接moment().valueOf()转出的时间戳其实是你当前所在时区计算出来的时间戳,而不是用户所选择的地区所属时区下得到的时间戳,因此,是需要有个计算的:
// 注: 假设用户使用的是antd datepicker,底层是基于momentjs来处理时间的/*** convert a datepicker value to desired region's timezone unix timestamp.* @param time usually retrieved from a datepicker* @param offset derived from timezone, eg. Asia/Shanghai's offset is '+08:00'* @return unix timestamp(seconds) ready for db storage.*/export const convertTZLocalDateToUnixTS = (time: moment.Moment,offset: string) => {let unixTS;if (time && offset) {// get the utc datestring, but drop timezone infoconst matchRet = time.format().match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);const localAsUTCFormat = matchRet ? matchRet[0] : '';unixTS = Math.floor(moment.parseZone(`${localAsUTCFormat}${offset}`).valueOf() / 1000);}return unixTS;};
举个例子,要想清楚,东八区的早上10点,其实是东七区的早上9点,那么如果当前运营人员在东八区,但是他要设置一个位于东七区的地区的早上9点触发的定时任务,他会在datepicker里选9点,那么其实我们不能以东八区的9点计算出来的时间戳传给后端(这是moment的默认行为),而是需要把用户界面上所选择的9点转化为东七区的9点,然后再计算时间戳,这才是正确的应该存储的时间。
那么对于时间的展现,其实也挺绕,比如服务器存的是unix timestamp,这玩意与时区无关(seconds since Jan 01 1970),那么,运营人员目前位于东八区,但是他需要切换到一个属于东七区的地区,查看一个定时任务的触发时间,那么,对于展现出来的时间信息,应该也要计算为东七区的时间才对:
import * as moment from 'moment-timezone';/*** convert a unix timestamp(seconds) into desired timezone date string for display,* can furtuer use this returned string to attend other needs* @param timestamp seconds* @param tz timezone string, eg. 'Asia/Shanghai', 'Asia/Jakarta', ...* @return YYYY-MM-DD HH:mm:SS date string*/export const convertUnixSecToTZLocalDateStr = (timestamp: number,tz: string): string => {// first convert to utc and then to desired timezone, then get the date stringreturn moment.unix(timestamp).utc().tz(tz).format('YYYY-MM-DD HH:mm:SS');};
