zoukankan      html  css  js  c++  java
  • 一起Polyfill系列:让Date识别ISO 8601日期时间格式

    一、什么是ISO 8601日期时间格式

      ISO 8601是国际标准化组织制定的日期时间表示规范,全称是《数据存储和交换形式·信息交换·日期和时间的表示方法》。

      示例:

      1. 2014-12-12T00:00:00.000Z

      2. 2014-12-12T00:00:00.000+08

      3. 2014-12-12T00:00:00.000+0800

      4. 2014-12-12T00:00:00.000+08:00

      5. 2004-W17-3

      6. 0001-165

    详细说明请参考度娘:http://baike.baidu.com/link?url=Qr7NLClAyUHihOCl1DK6DQL_gMw5rk3euXdiz3zt6M9ORGFS2XBy7LHmcO2ID-iz

    二、Javascript中实现的ISO 8601日期时间格式

      度娘后大家应该对ISO 8061有一定的了解了吧。ISO 8601的内容十分丰富,可惜Javascript仅仅实现一小部分而已,不过这一部分就够我们用了。

      javascript支持的ISO 8061格式如下:

       1. 2014-12-12T00:00:00.000Z

     2. 2014-12-12T00:00:00.000+0800

       3. 2014-12-12T00:00:00.000+08:00

    二、ES5中涉及ISO 8061日期时间格式的方法

     1.  Date.parse({String} datetime) :接收ISO 8061和GMT的日期时间格式字符串(根据格式内容被识别为0时区或其他时区的日期时间),返回入参所表示的0时区日期时间距离1970年1月1日的毫秒数。

       2.  Date.prototype.toISOString() :返回当前Date类型对象0时区的ISO 8061日期时间格式字符串。形如:2014-12-12T00:00:00.000Z

       3.  new Date({String} datetime) :构造函数的入参在ES5中新增接收ISO 8061格式字符串,其实内部就是调用 Date.parse({String} datetime) 进行转换。

       4.  Date.prototype.toJSON() :返回当前Date类型对象0时区的ISO 8061日期时间格式字符串。形如:2014-12-12T00:00:00.000Z。

    三、认识ES3下的Date类型

       1. 作为构造函数使用

    /**
      * 第一种入参模式:无入参,实例化当前日期时间的Date对象
      */
    var date1 = new Date();
     
    /**
      * 第二种入参模式:短日期格式字符串入参,实例化当前时区日期时间的Date对象
      */
    var date2 = new Date('2014/12/3');
     
    /**
      * 第三种入参模式:长日期格式字符串入参,实例化当前时区日期时间的Date对象
      */
    var date3 = new Date('Aug 3, 2014');
    
    /**
      * 第四种入参模式:GMT日期格式字符串入参,实例化指定时区日期时间的Date对象
      */
    var date4 = new Date('Tue May 25 2014 00:00:00 GMT +0800');
    
    /**
      * 第五种入参模式:GMT日期格式字符串入参,实例化0时区日期时间的Date对象
      */
    var date5 = new Date('Tue May 25 2014 00:00:00 GMT');
    
    /**
      * 第六种入参模式:入参依次为年、月、日、时、分、秒和毫秒的数值(其中仅年和月为必填项,日默认值为1,其他默认值为0),实例化当前时区日期时间的Date对象
      */
    var date6 = new Date(2014,12,2,1,1,1,1);

       2. 作为函数使用

    // 无论入参是什么,总返回当前时区的GMT日期时间格式的字符串
    var dateStr = Date();

       3. 类成员

         3.1.  Date.parse({String} datetime) :接收GMT的日期时间格式字符串(根据GMT格式内容被识别为0时区或其他时区的日期时间),返回入参所表示的0时区日期时间距离1970年1月1日的毫秒数

         3.2.  Date.UTC(Y,M,d,H,m,s,ms) :设置0时区的日期时间,返回入参所表示的0时区日期时间距离1970年1月1日的毫秒数

       4. 部分实例成员

      4.1.  Date.prototype.toGMTString() :返回当前Date对象的GMT日期时间格式字符串(仅为了向后兼容而已)

      4.2.  Date.prototype.toUTCString() :返回当前Date对象的GMT日期时间格式字符串(建议使用该方法)

    四、一起Polyfill

        if (!Date.prototype.toISOString){
            var isLeapYear = function(year){
                return (year % 400 === 0) || (year % 4 === 0 && year % 100 !== 0);
            };
            var operHoursAndMinutes = {}; 
            operHoursAndMinutes['+'] = function(minusHours, minusMinutes, year, month, date, hours, minutes, seconds, milliseconds){
                var ret = {};
                minutes -= minusMinutes;
                hours -= minusHours;
                if (minutes < 0){
                    hours -= 1;
                    minutes += 60;
                }
                if (hours < 0 ){
                    --date;
                    hours += 24;
                    if (date < 0){
                        --month;
                        if (month < 0){
                            --year;
                            month = 11;
                        }
                        if (month % 2 === 0){
                            date += 31;    
                        }
                        else if (month === 1)
                        {
                            date += isLeapYear(year) ? 29 : 28;
                        }
                        else{
                            date += 30;
                        }
    
                        if (month < 0){
                            --year;
                            month += 12;
                        }
                    }
                }
    
                ret.year = year;
                ret.month = month;
                ret.date = date;
                ret.hours = hours;
                ret.minutes = minutes;
                ret.seconds = seconds;
                ret.milliseconds = milliseconds;
    
                return ret;
            };
            operHoursAndMinutes['-'] = function(addHours, addMinutes, year, month, date, hours, minutes, seconds, milliseconds){
                var ret = {};
    
                minutes += addMinutes;
                hours += addHours;
                if (minutes >= 60){
                    hours += 1;
                    minutes -= 60;
                }
                if (hours >=24){
                    ++date;
                    hours -= 24;
                    var dateOfCurrMonth = month % 2 === 0 ? 31 : (month === 1 ? (isLeapYear(year) ? 29 : 28) : 30);
                    if (date >= dateOfCurrMonth){
                        ++month;
                        date -= dateOfCurrMonth;
    
                        if (month >= 12){
                            ++year;
                            month -= 12;
                        }
                    }
                }
    
                ret.year = year;
                ret.month = month;
                ret.date = date;
                ret.hours = hours;
                ret.minutes = minutes;
                ret.seconds = seconds;
                ret.milliseconds = milliseconds;
    
                return ret;
            };
            var regExp = new RegExp('^(\d{4,4})'
                    + '-((?:0[123456789]|1[012]))'
                    + '-((?:0[123456789]|[12]\d|3[01]))'
                    + 'T'
                    + '((?:[01]\d|2[0123]))'
                    + ':([012345]\d)'
                    + ':([012345]\d)'
                    + '(?:.(\d{3}))?'
                    + '(Z|[+-](?:[01]\d|2[0123]):?[012345]\d)$');
            var parseISOString2UTC = function(ISOString){
                var ret = {};
                var year = Number(RegExp.$1)
                    , month = Number(RegExp.$2) - 1
                    , date = Number(RegExp.$3)
                    , hours = Number(RegExp.$4)
                    , minutes = Number(RegExp.$5)
                    , seconds = Number(RegExp.$6)
                    , offset = RegExp.$8
                    , milliseconds;
                milliseconds = (milliseconds = Number(RegExp.$7), !isNaN(milliseconds) && milliseconds || 0);
    
                if (offset === 'Z'){     
                    ret.year = year;
                    ret.month = month;
                    ret.date = date;
                    ret.hours = hours;
                    ret.minutes = minutes;
                    ret.seconds = seconds;
                    ret.milliseconds = milliseconds;
                } 
                else if (typeof offset !== 'undefined'){     
                    var symbol = offset.charAt(0);
                    var offsetHours = Number(offset.substring(1,3));     
                    var offsetMinutes = Number(offset.substring(offset.length > 5 ? 4 : 3));
    
                    ret = operHoursAndMinutes[symbol](offsetHours, offsetMinutes, year, month, date, hours, minutes, seconds, milliseconds);
                }
    
                return ret;
            };
            
            var _nativeDate = Date;
            Date = function(Y,M,D,H,m,s,ms){
                var ret, len = arguments.length;
                if (!(this instanceof Date)){
                    ret = _nativeDate.apply(null, arguments);
                }
                else if (len === 1 && typeof arguments[0] === 'string' && regExp.test(arguments[0])){
                    var tmpRet;
                    try{
                        tmpRet = parseISOString2UTC();
                    }
                    catch(e){
                        console && console.log('Invalid Date');
                        return void 0;
                    }
    
                    ret = new _nativeDate(_nativeDate.UTC(tmpRet.year, tmpRet.month, tmpRet.date, tmpRet.hours, tmpRet.minutes, tmpRet.seconds, tmpRet.milliseconds));
                }
                else if (typeof arguments[0] === 'string'){
                    ret = new _nativeDate(arguments[0]);
                }
                else{
                    ret = len >= 7 ? new _nativeDate(Y, M, D, H, m, s, ms)
                        : len >= 6 ? new _nativeDate(Y, M, D, H, m, s)
                        : len >= 5 ? new _nativeDate(Y, M, D, H, m)
                        : len >= 4 ? new _nativeDate(Y, M, D, H)
                        : len >= 3 ? new _nativeDate(Y, M, D)
                        : len >= 2 ? new _nativeDate(Y, M)
                        : len >= 1 ? new _nativeDate(Y)
                        : new _nativeDate();
                }
    
                return ret;
            };
            Date.prototype = _nativeDate.prototype;
            Date.prototype.constructor = Date;
    
            var _pad = function(num){
                if (num < 10){
                    return '0' + num;
                }
                return num;
            };
            var _padMillisecond = function(num){
                if (num < 10){
                    return '00' + num;
                }
                else if (num < 100){
                    return '0' + num;
                }
                return num;
            };
            Date.prototype.toISOString = function(){
                    return [this.getUTCFullYear(), '-', _pad(this.getUTCMonth() + 1), '-', _pad(this.getUTCDate()), 'T'
                        , _pad(this.getUTCHours()), ':', _pad(this.getUTCMinutes()), ':', _pad(this.getUTCSeconds()), '.', _padMillisecond(this.getUTCMilliseconds()), 'Z'].join('');    
                };
    
            // 复制可枚举的类成员
            for (var clsProp in _nativeDate){
                if (_nativeDate.hasOwnProperty(clsProp)){
                    Date[clsProp] = _nativeDate[clsProp];
                }
            }
            // 复制不可枚举的类成员
            var innumerableMems = ['UTC'];
            for (var i = 0, clsProp; clsProp = innumerableMems[i++];){
                Date[clsProp] = _nativeDate[clsProp];
            }
    
            Date.parse = function(str){
                if (['string', 'number'].indexOf(typeof str) === -1) return NaN;
                
                var isMatch = regExp.test(str), milliseconds = 0;
                if (!isMatch) return _nativeDate.parse(str);
    
                var tmpRet = parseISOString2UTC();
    
                return _nativeDate.UTC(tmpRet.year, tmpRet.month, tmpRet.date, tmpRet.hours, tmpRet.minutes, tmpRet.seconds, tmpRet.milliseconds);
            };
            Date.now = Date.now 
                || function(){
                    return +new this();
                };
        }

    五、总结

      上述实现相对es5-shim来讲考虑的地方仍有欠缺,这源于我对日期时间格式的理解不够完整,因此请大家多多见谅。

    原创文章,转载请注明来自^_^肥仔John[http://fsjohnhuang.cnblogs.com]

    本文地址:http://www.cnblogs.com/fsjohnhuang/p/3731251.html (本篇完)

    如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!
      

  • 相关阅读:
    结构体排序中sort的自定义函数cmp()
    c++中清空输入缓冲区的方法(做cf的时候炸了)
    求第k小的数
    数论—约数
    HDU递归求解专题练习
    62、rdp报表
    61、inputTree
    60、list集合的各种姿势的排序
    59、table移动高亮
    13、docker安装nginx
  • 原文地址:https://www.cnblogs.com/fsjohnhuang/p/3731251.html
Copyright © 2011-2022 走看看