• 给出时间戳,根据指定时区,获取对应的时间字符串;
  • 给出字符串,根据指定时区,获取对应的时间戳;
  • 以上两种都需要展示出:时间字符串 + 时区,如:2019-12-02 02:00:01 +0800
  • 这里需要的时间格式字符串指的是:XXXX-XX-XX XX:XX:XX;
  • 指定时区为两种:一种是直接指定一个时区字符串,如:-08:00、+00:00,另一种是指定本地时区;
  • 由于 Date 构造函数对参数格式的要求,以及产品需求对数值展示时的格式要求,需将所计算的数值再次进行格式化处理;
  • 由于需要展示时区,以及获取本地时区与0时区的差用来做时区对应时间戳和事件字符串的换算,需要对本地时区与本地时区0时区差值进行计算。
  • 本地时区需要动态计算,而计算本地时区需要依靠原生方法,需要对原生方法生成时区相关的各种api进行了解和踩坑。
  • 字符串转时间戳

    * @date { str } 时间字符串 - '2015-01-01'、'2015-01-01 12'、 '2015-01-01 12:11'、'2015-01-01 12:12:12'格式 * @timeZone { str } 时区字符串 - '+04:00'、'+00:00'格式 * @returns { number } 按时区转换的时间戳 getAnyTimespan ( date, timeZone ) { if (! /^\d{5,}$/ . test (date)) { date = String (date) . replace ( /^([0-9]{4})$/ , '$1-01-01 00:00:00' ) . replace ( /^([0-9]{4}-[0-9]{2})$/ , '$1-01 00:00:00' ) . replace ( /^([0-9]{4}-[0-9]{2}-[0-9]{2})$/ , '$1 00:00:00' ) . replace ( /^([0-9]{4}-[0-9]{2}-[0-9]{2}\s[0-9]{2})$/ , '$1:00:00' ) date = new Date (date). getTime () return date - new Date (date). getTimezoneOffset () * 60 * 1000 - this . getOffsetMinute (timeZone) * 60 * 1000 ; return date; // 计算以分钟为单位的时区gap,例如 '+04:00'被转换为240 getOffsetMinute ( timeZone ) { if (! /^[+-][0-9]{2}:((0[0-9])|([1-5][0-9]))$/ . test (timeZone)) { // 与产品沟通,暂时使用较为严格的格式验证限制,缺少首位0和正负号视为非法格式 return 0 ; let time = timeZone. split ( ':' ); if (timeZone[ 0 ] === '-' ) { return parseInt (time[ 0 ]) * 60 - parseInt (time[ 1 ]. slice ( 0 , 2 )); //time[0]本身带正负号不需要加,time[1]不带需要加。 } else { return parseInt (time[ 0 ]) * 60 + parseInt (time[ 1 ]. slice ( 0 , 2 ));
  • getAnyTimespan 输入字符串,返回时间戳,步骤如下:
  • 判断是否是时间戳格式,已经是时间戳格式则自动原封不动返回传入时间戳;
  • 若传入参数不是时间戳,则视为时间字符串处理,步骤如下:
  • 将字符串处理为本地时间的时间戳(js没有提供直接将字符串转为指定时区时间戳的方法,由于每个月天数不一样,也较难直接通过字符串计算时间戳);
  • 格式化为字符串格式,防止报错阻断代码执行;
  • 利用repalce进行正则判断,补0为 Date 构造函数标准的参数格式;
  • 关于不标准的参数格式:
  • '2019' '2019-01' '2019-01-02' 仅有年月日的时间格式,会被按0时区转换为时间戳,而其他格式会按本地时区转为时间戳,并且其他有时分秒的格式无法直接获得0时区时间戳,所以必须转为 '2019-01-02 00:00:00' ,才可以获得统一的值;
  • '2019-01-02 00' 作为参数是非法时间格式;
  • 综上所述,将利用repalce统一补0;
  • 时间戳转字符串

    由于无法直接根据时间戳获取目标时区的时间字符串,每个月的天数不一样,直接计算出对应日期较为困难。我的思路是:根据本地时区和目标时区的时间差,计算出本地时区在目标时区当前时间的时间戳,进而通过new Date(默认转本地时间)获得目标时区当前时间。获取本地时间戳以获取所对应的年月日时分秒,并进行补0处理合成字符串。

    * @date { number } 时间戳 - 1564704000000格式 * @timeZone { str } 时区字符串 - '+04:00'、'+00:00'格式 * @returns { str } - '2015-01-01 12:12:12'格式 getAnyTimeString ( date, timeZone ) { let sameTimelocalTimeStamp = date - 0 + new Date (date). getTimezoneOffset () * 60 * 1000 + this . getOffsetMinute (timeZone) * 60 * 1000 ; let targetTime = new Date (sameTimelocalTimeStamp) let targetTimeString = String (targetTime. getFullYear ()) + '-' + String (targetTime. getMonth () + 1 ). replace ( /^(\d)$/ , '0$1' ) + '-' + String (targetTime. getDate ()). replace ( /^(\d)$/ , '0$1' ) + ' ' + String (targetTime. getHours ()). replace ( /^(\d)$/ , '0$1' ) + ':' + String (targetTime. getMinutes ()). replace ( /^(\d)$/ , '0$1' ) + ':' + String (targetTime. getSeconds ()). replace ( /^(\d)$/ , '0$1' ) return targetTimeString;

    时区的计算

    由于时区需要被单独展示出来,所以这里提供了时区的计算方法。代码中case1、case2都是给出指定的时区字符串,这里不做分析。仅在获取默认值本地时区时,需要注意一些细节。

        timeZone() {
            switch (this.timeZoneType) { // 时间控件无论是否支持多时区(发送时间戳)都默认本地时区,可配置其他
                case 1:
                    return '+00:00';
                case 2:
                    return this.activeTimeZone;
                default:
                    let timegapHour = String(0 - Math.floor(new Date(date).getTimezoneOffset()/60)) // 获取小时
                        .replace(/^([+-]?)(\d)$/, '$1' + 0 + '$2') // 单数小时补0
                        .replace(/^(\d+)$/, '+' + '$1'); // 整数小时补+号
                    let timegapMinute = String(Math.abs(new Date(date).getTimezoneOffset()%60)) // 获取分钟
                        .replace(/^(\d)$/, 0 + '$1'); // 单数分钟补0
                    return `${timegapHour}:${timegapMinute}`;
    
  • 通过new Date(date).getTimezoneOffset()获取时区差值时,仍需要注意传入要转换的时间。同一地区,展示的时间不同时,若时间的夏令时不同,则时区不同。
  • 对于算出的小时数值进行补0补+号处理;
  • 本次功能的实现,在格式化部分,均使用正则方法对字符串和数字格式进行处理。在时区对应值的计算上,均使用0时区作为媒介,获取时间差进行计算。需要注意的是夏令时时区与时区差的获取,必须传入具体时间作为参数,才可以避免由于夏令时产生的1小时偏差的影响。若一个时间控件使用此类多时区转换的功能,当用户选择一个夏令时和非夏令时时,若对应的是本地时区,则时区具体数值将随着是否夏令时而变化。

    欢迎大家针对我的代码进行交流学习,提出更好的优化建议。

    分类:
    前端
    标签: