以前一直都是开发国内业务,还真没遇到要处理时区的场景,shopee这边则不同,一个管理后台会按国家维度来做数据划分,最终也会交给不同国家的运营人员来维护,那么比如对于一个定时任务,则各地的运营人员需要清晰的知道该任务生效的时间(当地时间),其实概念有点绕的,作为开发人员,你面对的是你所在的时区里的时间,但你要站在对方的时区去思考这个问题,创建定时任务时,用户在datepicker里所选择的时间其实是他期望的当地时间,但momentjs默认会以你系统的时区来处理时间,所以,你如果直接moment().valueOf()转出的时间戳其实是你当前所在时区计算出来的时间戳,而不是用户所选择的地区所属时区下得到的时间戳,因此,是需要有个计算的:

    1. // 注: 假设用户使用的是antd datepicker,底层是基于momentjs来处理时间的
    2. /**
    3. * convert a datepicker value to desired region's timezone unix timestamp.
    4. * @param time usually retrieved from a datepicker
    5. * @param offset derived from timezone, eg. Asia/Shanghai's offset is '+08:00'
    6. * @return unix timestamp(seconds) ready for db storage.
    7. */
    8. export const convertTZLocalDateToUnixTS = (
    9. time: moment.Moment,
    10. offset: string
    11. ) => {
    12. let unixTS;
    13. if (time && offset) {
    14. // get the utc datestring, but drop timezone info
    15. const matchRet = time.format().match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);
    16. const localAsUTCFormat = matchRet ? matchRet[0] : '';
    17. unixTS = Math.floor(
    18. moment.parseZone(`${localAsUTCFormat}${offset}`).valueOf() / 1000
    19. );
    20. }
    21. return unixTS;
    22. };

    举个例子,要想清楚,东八区的早上10点,其实是东七区的早上9点,那么如果当前运营人员在东八区,但是他要设置一个位于东七区的地区的早上9点触发的定时任务,他会在datepicker里选9点,那么其实我们不能以东八区的9点计算出来的时间戳传给后端(这是moment的默认行为),而是需要把用户界面上所选择的9点转化为东七区的9点,然后再计算时间戳,这才是正确的应该存储的时间。

    那么对于时间的展现,其实也挺绕,比如服务器存的是unix timestamp,这玩意与时区无关(seconds since Jan 01 1970),那么,运营人员目前位于东八区,但是他需要切换到一个属于东七区的地区,查看一个定时任务的触发时间,那么,对于展现出来的时间信息,应该也要计算为东七区的时间才对:

    1. import * as moment from 'moment-timezone';
    2. /**
    3. * convert a unix timestamp(seconds) into desired timezone date string for display,
    4. * can furtuer use this returned string to attend other needs
    5. * @param timestamp seconds
    6. * @param tz timezone string, eg. 'Asia/Shanghai', 'Asia/Jakarta', ...
    7. * @return YYYY-MM-DD HH:mm:SS date string
    8. */
    9. export const convertUnixSecToTZLocalDateStr = (
    10. timestamp: number,
    11. tz: string
    12. ): string => {
    13. // first convert to utc and then to desired timezone, then get the date string
    14. return moment
    15. .unix(timestamp)
    16. .utc()
    17. .tz(tz)
    18. .format('YYYY-MM-DD HH:mm:SS');
    19. };