jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
Optimizations for Moment string interpretation
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
var DEFAULT_TZ = 'Asia/Tokyo';
var ISO_8601_DATE_REGEXP = /^(\d{4})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?((?:\-|\+)(?:\d{2}):(?:\d{2})))?)?)?$/;
var DEFAULT_DATE_FORMATS = {
'HH:mm:ss': {
regex: /^(\d{2}):(\d{2}):(\d{2})$/,
match: ['hour', 'minute', 'second']
},
"M/D/YYYY": {
regex: /^([01]?\d)\/([0-3]?\d)\/(\d{4})$/,
match: ["month", "day", "year"]
},
"M/D/YYYY HH:mm A": {
regex: /^([01]?\d)\/([0-3]?\d)\/(\d{4}) (\d{2}):(\d{2}) ([aApP][mM])$/,
match: ["month", "day", "year", "hour", "minute", "ampm"]
}
};
function oldCompare(date1, date2)
{
date1 = toMoment(date1);
date2 = toMoment(date2);
return date1 && date2 && (date1.valueOf() - date2.valueOf());
}
function newCompare(date1, date2)
{
if(!date1 || !date2)
{
return 0;
}
var date1IsString = isString(date1);
var date2IsString = isString(date2);
var match1 = date1IsString && date1.match(ISO_8601_DATE_REGEXP);
var match2 = date2IsString && date2.match(ISO_8601_DATE_REGEXP);
var date1Timestamp = NaN;
var date2Timestamp = NaN;
if(date1IsString && date2IsString && match1 && match2)
{
var date1Tz = match1[match1.length - 1] || '+00:00';
date1Timestamp = match1[1] + (match1[2] || '01') + (match1[3] || '01') + (match1[4] || '00')
+ (match1[5] || '00') + (match1[6] || '00');
var date2Tz = match2[match2.length - 1] || '+00:00';
date2Timestamp = match2[1] + (match2[2] || '01') + (match2[3] || '01') + (match2[4] || '00')
+ (match2[5] || '00') + (match2[6] || '00');
if(!date1Tz || !date2Tz)
{
date1Timestamp = NaN;
date2Timestamp = NaN;
}
else if(date1Tz != date2Tz)
{
var hasTz = date1.indexOf('T') >= 0;
date1 = new Date(date1);
if(!hasTz)
{
date1.setTime(date1.getTime() + date1.getTimezoneOffset()*60000);
}
hasTz = date2.indexOf('T') >= 0;
date2 = new Date(date2);
if(!hasTz)
{
date2.setTime(date2.getTime() + date2.getTimezoneOffset()*60000);
}
date1Timestamp = date1.valueOf();
date2Timestamp = date2.valueOf();
}
}
else
{
if(match1)
{
hasTz = date1.indexOf('T') >= 0;
date1 = new Date(date1);
if(!hasTz)
{
date1.setTime(date1.getTime() + date1.getTimezoneOffset()*60000);
}
}
if(match2)
{
hasTz = date2.indexOf('T') >= 0;
date2 = new Date(date2);
if(!hasTz)
{
date2.setTime(date2.getTime() + date2.getTimezoneOffset()*60000);
}
}
date1Timestamp = moment.isMoment(date1) || isDate(date1) ? date1.valueOf() : NaN;
date2Timestamp = moment.isMoment(date2) || isDate(date2) ? date2.valueOf() : NaN;
}
if(isNaN(date1Timestamp))
{
if(date1 = moment.isMoment(date1) ? date1 : toMoment(date1))
{
date1Timestamp = date1.valueOf();
}
else
{
return false;
}
}
if(isNaN(date2Timestamp))
{
if(date2 = moment.isMoment(date2) ? date2 : toMoment(date2))
{
date2Timestamp = date2.valueOf();
}
else
{
return false;
}
}
return date1Timestamp - date2Timestamp;
}
function toMoment(date, formats, tz)
{
var found = false;
tz = tz || DEFAULT_TZ;
if(date === false || date === null)
{
return false;
}
if(isString(date))
{
if(date == 'now')
{
return moment.tz(tz);
}
date = $.trim(date);
var found;
if(found = date.match(ISO_8601_DATE_REGEXP))
{
var hasTz = date.indexOf('T') >= 0;
var tmpDate = new Date(date);
date = moment.tz(tmpDate, tz);
if(!hasTz)
{
date.add(date.zone(), 'minutes');
}
}
else
{
formats = $.extend({}, DEFAULT_DATE_FORMATS, formats || {});
$.each(formats, function(format, regex){
if(found = date.match(regex.regex || regex))
{
if(regex.match)
{
var dateObj = {year: 1970, month: 1, day: 1, hour: 0, minute: 0, second: 0};
for(var i = 0; i < regex.match.length; i++)
{
dateObj[regex.match[i]] = found[i + 1];
}
if(dateObj.ampm && dateObj.hour)
{
if(dateObj.hour == 12)
{
if(dateObj.ampm.charAt(0).toLowerCase() == 'a')
{
dateObj.hour = 0;
}
}
else if(dateObj.ampm.charAt(0).toLowerCase() == 'p')
{
dateObj.hour = parseInt(dateObj.hour) + 12;
}
}
var tmpDate = new Date(dateObj.year, dateObj.month - 1, dateObj.day, dateObj.hour, dateObj.minute, dateObj.second);
date = moment.tz(tmpDate, tz);
date.subtract(tmpDate.getTimezoneOffset() - date.zone(), 'minutes');
}
else
{
date = moment.tz(date, format, tz);
}
return false;
}
});
}
if(!found)
{
return false;
}
}
else if(moment.isMoment(date))
{
date = date.clone().tz(tz);
}
else
{
date = moment.tz(date, tz);
}
return moment.isMoment(date) && date.isValid() && date;
}
function isString(value){return typeof value == 'string';}
function isDate(value){
return Object.prototype.toString.call(value) === '[object Date]';
}
if (!Date.prototype.printf)
{
Date.prototype.printf = (function ()
{
function pad(number)
{
var r = String(number);
if (r.length === 1)
{
r = '0' + r;
}
return r;
}
return function (format)
{
var d = this.getDate(),
D = this.getDay(),
m = this.getMonth(),
y = this.getFullYear(),
h = this.getHours(),
M = this.getMinutes(),
s = this.getSeconds(),
tzOff = this.getTimezoneOffset(),
U = Math.floor(this.getTime() / 1000),
self = this,
escaped = false,
leap = ((0 == (y % 4)) && ((0 != (y % 100)) || (0 == (y % 400))));
return $.map(format.split(''),function (part)
{
if (escaped)
{
escaped = false;
return part;
}
switch (part)
{
case '\\':
escaped = true;
return "";
// Day
case "d":
return pad(d);
case "D":
return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][D];
case "j":
return d;
case "l":
return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][D];
case "N":
return D == 0 ? 7 : D;
case "S":
return ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10];
case "w":
return D;
case "z":
var ret = 0;
$.each([31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30], function (key, val)
{
if (key == m)
{
return false;
}
ret += val;
});
return ret + (d - 1);
// Week
case "W":
return function (date)
{
date.setDate(d - (D + 6) % 7 + 3); // Nearest Thu
var ms = date.valueOf(); // GMT
date.setMonth(0);
date.setDate(4); // Thu in Week 1
return Math.round((ms - date.valueOf()) / (7 * 864e5)) + 1;
}(self);
// Month
case "F":
return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
'September', 'October', 'November', 'December'][m];
case "m":
return pad(m + 1);
case "M":
return ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][m];
case "n":
return m + 1;
case "t":
return [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][m];
// Year
case "L":
return leap ? 1 : 0;
//case "o": return y; // almost always the same as Y but not really so leave it for someone else
case "y":
return String(y).substr(2, 2);
case "Y":
return y;
// Time
case "a":
return h < 12 ? 'am' : 'pm';
case "A":
return h < 12 ? 'AM' : 'PM';
case "g":
return (h - 1) % 12 + 1;
case "G":
return h;
case "h":
return pad((h - 1) % 12 + 1);
case "H":
return pad(h);
case "i":
return pad(M);
case "s":
return pad(s);
// Timezone
case "O":
var abs = Math.abs(tzOff);
return (tzOff <= 0 ? "+" : "-") + pad(Math.floor(abs / 60)) + pad(abs % 60);
case "P":
var abs = Math.abs(tzOff);
return (tzOff <= 0 ? "+" : "-") + pad(Math.floor(abs / 60)) + ":" + pad(abs % 60);
case "Z":
return tzOff * 60;
// Full Date/Time
case "c":
return self.printf("Y-m-d\\TH:i:sP");
case "r":
return self.printf("D, d M Y H:i:s O");
case "U":
return U;
default:
return part;
}
}).join('');
};
})();
}
function printfParams(moment){
var split = moment.format("d Do YYYY M").split(' ');
var leap = ((0 == (split[2] % 4)) && ((0 != (split[2] % 100)) || (0 == (split[2] % 400))));
return {
N: split[0] == 0 ? 7 : split[0],
S: '[' + split[1].substr(-2) + ']',
t: [null, 31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][split[3]],
L: leap ? 1 : 0
};
}
$.extend(moment, {
convertPrintfToFormat: function(format){
var newFormat = '';
var extras = false;
var addSeparator = false;
for(var i = 0; i < format.length; i++)
{
var char = format[i];
if(char == '\\')
{
newFormat += char + format[++i];
continue;
}
if(char == '[')
{
newFormat += "\\" + char;
continue;
}
var prevAddSeparator = addSeparator;
addSeparator = true;
var newChar = null;
switch(char)
{
// Day
case "d": newChar = 'DD'; break;
case "D": newChar = 'ddd'; break;
case "j": newChar = 'D'; break;
case "l": newChar = 'dddd'; break;
case "N": newChar = (extras || (extras = printfParams(this)))[char]; addSeparator = false; break;
case "S": newChar = (extras || (extras = printfParams(this)))[char]; addSeparator = false; break;
case "w": newChar = 'd'; break;
case "z": newChar = 'DDD'; break;
// Week
case 'W': newChar = 'w'; break;
// Month
case 'F': newChar = 'MMMM'; break;
case 'm': newChar = 'MM'; break;
case 'M': newChar = 'MMM'; break;
case 'n': newChar = 'M'; break;
case "t": newChar = (extras || (extras = printfParams(this)))[char]; addSeparator = false; break;
// Year
case "L": newChar = (extras || (extras = printfParams(this)))[char]; addSeparator = false; break;
// case "o": ???
case 'Y': newChar = 'YYYY'; break;
case 'y': newChar = 'YY'; break;
// Time
case 'a': newChar = 'a'; break;
case 'A': newChar = 'A'; break;
// case "B": ???
case 'g': newChar = 'h'; break;
case 'G': newChar = 'H'; break;
case 'h': newChar = 'hh'; break;
case 'H': newChar = 'HH'; break;
case 'i': newChar = 'mm'; break;
case 's': newChar = 'ss'; break;
// case "u": newChar = 'SSS000'; break; <-- Close but not truly accurate
// Timezone
case "e": newChar = 'zz'; break;
case "I": newChar = this.isDST() ? 1 : 0; addSeparator = false; break;
case "O": newChar = 'ZZ'; break;
case "P": newChar = 'Z'; break;
case "T": newChar = 'z'; break;
case "Z": newChar = this.zone() * 60; addSeparator = false; break;
// Full Date/Time
case "c": newChar = 'YYYY-MM-DD\\THH:mm:ssZ'; break;
case "r": newChar = 'ddd, DD MMM YYYY HH:mm:ss ZZ'; break;
case "U": newChar = 'X'; break;
default:
addSeparator = false;
if(char.match(/[A-Za-z]/))
{
newChar = '[' + char + ']';
}
else
{
newChar = char;
}
break;
}
if(addSeparator && prevAddSeparator)
{
newFormat += '[]';
}
newFormat += newChar;
}
return newFormat;
}
});
$.extend(moment.fn, {
printf: function(format){
return this.format(moment.convertPrintfToFormat(format));
}
});
var firstDate = new Date('2014-02-23T01:02:03-05:00');
var firstMoment = toMoment(new Date('2014-02-23T01:02:03-05:00'));
var secondDate = new Date('2015-03-24T02:03:04-05:00');
var secondMoment = toMoment(new Date('2015-03-24T02:03:04-05:00'));
Ready to run.
Test | Ops/sec | |
---|---|---|
New ISO-8601 w/Same Timezone |
| ready |
Old ISO-8601 w/Same Timezone |
| ready |
New ISO-8601 w/Different Timezone |
| ready |
Old ISO-8601 w/Different Timezone |
| ready |
New ISO and Date |
| ready |
Old ISO and Date |
| ready |
New ISO and Moment |
| ready |
Old ISO and Moment |
| ready |
New Date and Moment |
| ready |
Old Date and Moment |
| ready |
New 2 Moments |
| ready |
Old 2 Moments |
| ready |
New 2 Dates |
| ready |
Old 2 Dates |
| ready |
New ISO and Date |
| ready |
Old ISO and Date |
| ready |
New non-ISO |
| ready |
Old non-ISO |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.