JavaScript框架设计
上QQ阅读APP看书,第一时间看更新

3.5 日期的扩展与修复

Date构造器是JavaScript中传参形式最丰富的构造器,大致分为四种。

      new Date();
      new Date(value);//传入毫秒数
      new Date(dateString);
      new Date(year, month, day /*, hour, minute, second, millisecond*/);

其中第三种可以玩N多花样,个人建议只使用“2009/07/12 12:34:56 ”,后面的时分秒可省略。这个所有浏览器都支持。此构造器的兼容列表可见此文:

http://dygraphs.com/date-formats.html

若要修正它的传参,这恐怕是个大工程,要整个对象替换掉,并且影响Object.prototype.toString的类型判定。因此不建议修正。es5.js中有相关源码,大家可以看这里:

https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js

JavaScript的日期是抄自Java的java.util.Date,但是Date这个类中的很多方法对时区等支持不够,且不少都是已过时,Java程序员也推荐使用calnedar类代替Date类。JavaScript可选择的余地比较少,只能捏着鼻子继续用。如对属性使用了前后矛盾的偏移量。月份与小时都是基于0,月份中的天数则是基于1,而年则是从1900开始的。

接着下来,我们为旧版本浏览器添加几个ecma262标准化的日期方法吧。

      if (!Date.now) {
          Date.now = function() {
              return +new Date;
          }
      }
      if (!Date.prototype.toISOString) {
          void function() {
              function pad(number) {
                  var r = String(number);
                  if (r.length === 1) {
                      r = '0' + r;
                  }
                  return r;
              }
              Date.prototype.toJSON = Date.prototype.toISOString = function() {
                  return this.getUTCFullYear()
                          + '-' + pad(this.getUTCMonth() + 1)
                          + '-' + pad(this.getUTCDate())
                          + 'T' + pad(this.getUTCHours())
                          + ':' + pad(this.getUTCMinutes())
                          + ':' + pad(this.getUTCSeconds())
                          + '.' + String((this.getUTCMilliseconds() / 1000).toFixed(3)).slice(2, 5)
                          + 'Z';
              };
          }();
      }

IE6、IE7中,getYear、setYear方法存在BUG,这个修起来比较简单。

      if ((new Date).getYear() > 1900) {
          Date.prototype.getYear = function() {
              return this.getFullYear() - 1900;
          };
          Date.prototype.setYear = function(year) {
              return this.setFullYear(year); //+ 1900
          };
      }

至于扩展,由于涉及本地化的原因,外国许多日期库都需要改一改才能用,其中以 dataFormat这个很有用的方法为最。我先给一些常用的扩展吧。

传入两个Date类型的日期,求出它们相隔多少天。

      var getDatePeriod = function(start, finish) {
          return Math.abs(start * 1 - finish * 1) / 60 / 60 / 1000 / 24;
      }

传入一个Date类型的日期,求出它所在月的第一天。

      var getFirstDateInMonth = function(date) {
          return new Date(date.getFullYear(), date.getMonth(), 1);
      }

传入一个Date类型的日期,求出它所在月的最后一天。

      var getLastDateInMonth = function(date) {
          return new Date(date.getFullYear(), date.getMonth() + 1, 0);
      }

传入一个Date类型的日期,求出它所在季度的第一天。

      var getFirstDateInQuarter = function(date) {
          return new Date(date.getFullYear(), ~~(date.getMonth() / 3) * 3, 1);
      }

传入一个Date类型的日期,求出它所在季度的最后一天。

      var getFirstDateInQuarter = function(date) {
          return new Date(date.getFullYear(), ~~(date.getMonth() / 3) * 3 + 3, 0);
      }

判断是否为闰年。

      Date.prototype.isLeapYear = function() {
          return new Date(this.getFullYear(), 2, 0).getDate() == 29;
      }

取得当前月份的天数。

      function getDaysInMonth1(date) {
          switch (date.getMonth()) {
              case 0:
              case 2:
              case 4:
              case 6:
              case 7:
              case 9:
              case 11:
                  return 31;
              case 1:
                  var y = date.getFullYear();
                  return y % 4 == 0 && y % 100 != 0 || y % 400 == 0 ? 29 : 28;
              default:
                  return 30;
          }
      }
      function getDaysInMonth2(date) {
          switch (date.getMonth()) {
              case 0:
              case 2:
              case 4:
              case 6:
              case 7:
              case 9:
              case 11:
                  return 31;
              case 1:
                  var y = date.getFullYear();
                  return y % 4 == 0 && y % 100 != 0 || y % 400 == 0 ? 29 : 28;
              default:
                  return 30;
          }
      }
      function getDaysInMonth3(date) {
          return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
      }

最后是dateForamt方法,由于太长了,我也不便贴出来,可到以下链接查看:

https://github.com/RubyLouvre/mass-Framework/blob/1.41/avalon.js