Date formatting (v6)

Revision 6 of this benchmark created on


Description

A comparison of different date libraries and their formatting functions.

Preparation HTML

<!-- Store native Date.toString as DateJS overrides it -->
<script>
  var nativeDateToString = Date.prototype.toString;
</script>
<script src="https://raw.github.com/datejs/Datejs/master/build/date.js">
</script>
<script>
  Date.prototype.dateJSFormat = Date.prototype.toString;
  Date.prototype.toString = nativeDateToString;
</script>
<!-- DateTimeJS -->
<script src="https://raw.github.com/geoffreymcgill/datetimejs/master/src/datetime.min.js"></script>
<script>
  // Changed this format slightly, so we don't pre-cache the same
  // format used in "Test 7". This format will be used in "Test 8".
  var test8 = DateTime.formatFn("MM-dd-yyyy hh:mm:ss tt");
</script>

<!-- xdate -->
<script src="https://raw.github.com/arshaw/xdate/master/src/xdate.js">
</script>
<!-- phpjs -->
<script src="https://raw.github.com/kvz/phpjs/master/functions/datetime/date.js">
</script>
<!-- MomentJS -->
<script src="https://raw.github.com/timrwood/moment/master/moment.js">
</script>
<!-- Jacob Wright -->
<script>
  Date.prototype.jwFormat = function(format) {
    var returnStr = '';
    var replace = Date.replaceChars;
    for (var i = 0; i < format.length; i++) {
      var curChar = format.charAt(i);
      if (i - 1 >= 0 && format.charAt(i - 1) == "\\") {
        returnStr += curChar;
      } else if (replace[curChar]) {
        returnStr += replace[curChar].call(this);
      } else if (curChar != "\\") {
        returnStr += curChar;
      }
    }
    return returnStr;
  };

  Date.replaceChars = {
    shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
    longMonths: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
    shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
    longDays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],

    // Day
    d: function() {
      return (this.getDate() < 10 ? '0' : '') + this.getDate();
    },
    D: function() {
      return Date.replaceChars.shortDays[this.getDay()];
    },
    j: function() {
      return this.getDate();
    },
    l: function() {
      return Date.replaceChars.longDays[this.getDay()];
    },
    N: function() {
      return this.getDay() + 1;
    },
    S: function() {
      return (this.getDate() % 10 == 1 && this.getDate() != 11 ? 'st' : (this.getDate() % 10 == 2 && this.getDate() != 12 ? 'nd' : (this.getDate() % 10 == 3 && this.getDate() != 13 ? 'rd' : 'th')));
    },
    w: function() {
      return this.getDay();
    },
    z: function() {
      var d = new Date(this.getFullYear(), 0, 1);
      return Math.ceil((this - d) / 86400000);
    },
    // Fixed now
    // Week
    W: function() {
      var d = new Date(this.getFullYear(), 0, 1);
      return Math.ceil((((this - d) / 86400000) + d.getDay() + 1) / 7);
    },
    // Fixed now
    // Month
    F: function() {
      return Date.replaceChars.longMonths[this.getMonth()];
    },
    m: function() {
      return (this.getMonth() < 9 ? '0' : '') + (this.getMonth() + 1);
    },
    M: function() {
      return Date.replaceChars.shortMonths[this.getMonth()];
    },
    n: function() {
      return this.getMonth() + 1;
    },
    t: function() {
      var d = new Date();
      return new Date(d.getFullYear(), d.getMonth(), 0).getDate()
    },
    // Fixed now, gets #days of date
    // Year
    L: function() {
      var year = this.getFullYear();
      return (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0));
    },
    // Fixed now
    o: function() {
      var d = new Date(this.valueOf());
      d.setDate(d.getDate() - ((this.getDay() + 6) % 7) + 3);
      return d.getFullYear();
    },
    //Fixed now
    Y: function() {
      return this.getFullYear();
    },
    y: function() {
      return ('' + this.getFullYear()).substr(2);
    },
    // Time
    a: function() {
      return this.getHours() < 12 ? 'am' : 'pm';
    },
    A: function() {
      return this.getHours() < 12 ? 'AM' : 'PM';
    },
    B: function() {
      return Math.floor((((this.getUTCHours() + 1) % 24) + this.getUTCMinutes() / 60 + this.getUTCSeconds() / 3600) * 1000 / 24);
    },
    // Fixed now
    g: function() {
      return this.getHours() % 12 || 12;
    },
    G: function() {
      return this.getHours();
    },
    h: function() {
      return ((this.getHours() % 12 || 12) < 10 ? '0' : '') + (this.getHours() % 12 || 12);
    },
    H: function() {
      return (this.getHours() < 10 ? '0' : '') + this.getHours();
    },
    i: function() {
      return (this.getMinutes() < 10 ? '0' : '') + this.getMinutes();
    },
    s: function() {
      return (this.getSeconds() < 10 ? '0' : '') + this.getSeconds();
    },
    u: function() {
      var m = this.getMilliseconds();
      return (m < 10 ? '00' : (m < 100 ? '0' : '')) + m;
    },
    // Timezone
    e: function() {
      return "Not Yet Supported";
    },
    I: function() {
      return "Not Yet Supported";
    },
    O: function() {
      return (-this.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(this.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(this.getTimezoneOffset() / 60)) + '00';
    },
    P: function() {
      return (-this.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(this.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(this.getTimezoneOffset() / 60)) + ':00';
    },
    // Fixed now
    T: function() {
      var m = this.getMonth();
      this.setMonth(0);
      var result = this.toTimeString().replace(/^.+ \(?([^\)]+)\)?$/, '$1');
      this.setMonth(m);
      return result;
    },
    Z: function() {
      return -this.getTimezoneOffset() * 60;
    },
    // Full Date/Time
    c: function() {
      return this.format("Y-m-d\\TH:i:sP");
    },
    // Fixed now
    r: function() {
      return this.toString();
    },
    U: function() {
      return this.getTime() / 1000;
    }
  };
</script>
<!-- steven levithan -->
<script>
  /*
 * Date Format 1.2.3
 * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
 * MIT license
 *
 * Includes enhancements by Scott Trenda <scott.trenda.net>
 * and Kris Kowal <cixar.com/~kris.kowal/>
 *
 * Accepts a date, a mask, or a date and a mask.
 * Returns a formatted version of the given date.
 * The date defaults to the current date/time.
 * The mask defaults to dateFormat.masks.default.
 */

  var dateFormat = function() {
      var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
          timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
          timezoneClip = /[^-+\dA-Z]/g,
          pad = function(val, len) {
          val = String(val);
          len = len || 2;
          while (val.length < len) val = "0" + val;
          return val;
          };

      // Regexes and supporting functions are cached through closure
      return function(date, mask, utc) {
        var dF = dateFormat;

        // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
        if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
          mask = date;
          date = undefined;
        }

        // Passing date through Date applies Date.parse, if necessary
        date = date ? new Date(date) : new Date;
        if (isNaN(date)) throw SyntaxError("invalid date");

        mask = String(dF.masks[mask] || mask || dF.masks["default"]);

        // Allow setting the utc argument via the mask
        if (mask.slice(0, 4) == "UTC:") {
          mask = mask.slice(4);
          utc = true;
        }

        var _ = utc ? "getUTC" : "get",
            d = date[_ + "Date"](),
            D = date[_ + "Day"](),
            m = date[_ + "Month"](),
            y = date[_ + "FullYear"](),
            H = date[_ + "Hours"](),
            M = date[_ + "Minutes"](),
            s = date[_ + "Seconds"](),
            L = date[_ + "Milliseconds"](),
            o = utc ? 0 : date.getTimezoneOffset(),
            flags = {
            d: d,
            dd: pad(d),
            ddd: dF.i18n.dayNames[D],
            dddd: dF.i18n.dayNames[D + 7],
            m: m + 1,
            mm: pad(m + 1),
            mmm: dF.i18n.monthNames[m],
            mmmm: dF.i18n.monthNames[m + 12],
            yy: String(y).slice(2),
            yyyy: y,
            h: H % 12 || 12,
            hh: pad(H % 12 || 12),
            H: H,
            HH: pad(H),
            M: M,
            MM: pad(M),
            s: s,
            ss: pad(s),
            l: pad(L, 3),
            L: pad(L > 99 ? Math.round(L / 10) : L),
            t: H < 12 ? "a" : "p",
            tt: H < 12 ? "am" : "pm",
            T: H < 12 ? "A" : "P",
            TT: H < 12 ? "AM" : "PM",
            Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
            o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
            S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
            };

        return mask.replace(token, function($0) {
          return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
        });
      };
      }();

  // Some common format strings
  dateFormat.masks = {
    "default": "ddd mmm dd yyyy HH:MM:ss",
    shortDate: "m/d/yy",
    mediumDate: "mmm d, yyyy",
    longDate: "mmmm d, yyyy",
    fullDate: "dddd, mmmm d, yyyy",
    shortTime: "h:MM TT",
    mediumTime: "h:MM:ss TT",
    longTime: "h:MM:ss TT Z",
    isoDate: "yyyy-mm-dd",
    isoTime: "HH:MM:ss",
    isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
    isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
  };

  // Internationalization strings
  dateFormat.i18n = {
    dayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
    monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
  };

  // For convenience...
  Date.prototype.steveFormat = function(mask, utc) {
    return dateFormat(this, mask, utc);
  };
</script>
<script>
  var m = moment();
  var d = new Date();
  var t = Math.round(+d / 1000);
  var x = new XDate();
  var y = new DateTime();

  if (console && console.log) {
    console.log(m.format('MM-DD-YYYY h:mm:ss a'), 'MomentJS format');
    console.log(d.dateJSFormat('MM-dd-yyyy h:mm:ss tt'), 'DateJS format');
    console.log(y.format('MM-dd-yyyy h:mm:ss tt'), 'DateTimeJS format');
    console.log(test8(y), 'DateTimeJS optimized format');
    console.log(d.jwFormat('m-d-Y g:i:s a'), 'Jacob Wright format');
    console.log(d.steveFormat('mm-dd-yyyy h:MM:ss tt'), 'Steve Levithan format');
    console.log(date('m-d-Y g:i:s a', t), 'phpjs format');
    console.log(x.toString('MM-dd-yyyy h:mm:ss tt'), 'xdate format');
  }
</script>

Test runner

Ready to run.

Testing in
TestOps/sec
MomentJS
m.format('MM-DD-YYYY h:mm:ss a');
ready
DateJS
d.dateJSFormat('MM-dd-yyyy h:mm:ss t');
ready
Jacob Wright
d.jwFormat('m-d-Y g:i:s a');
ready
Steve Levithan
d.steveFormat('mm-dd-yyyy h:MM:ss tt');
ready
phpjs
date('m-d-Y g:i:s a', t);
ready
XDate
x.toString('MM-dd-yyyy h:mm:ss tt')
ready
DateTimeJS
y.format("MM-dd-yyyy h:mm:ss tt")
ready
DateTimeJS Optimized (High Speed)
test8(y);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.