-
-
Save mattjohnsonpint/f6aa5e8b8aa040f65ae1 to your computer and use it in GitHub Desktop.
| var d365 = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 ]; | |
| var d366 = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 ]; | |
| function parts2ts(year, month, day, hour, minute, second, millisecond) { | |
| if (month < 0 || month > 11) { | |
| return NaN; | |
| } | |
| var leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); | |
| var days = leap ? d366 : d365; | |
| if (day < 1 || day > days[month + 1] - days[month]) { | |
| return NaN; | |
| } | |
| var f = Math.floor; | |
| var y = year - 1; | |
| var daysSinceEpoch = y * 365 + f(y / 4) - f(y / 100) + f(y / 400) + days[month] + day - 719163; | |
| return (daysSinceEpoch * 8640 * 10000) + (hour * 3600 * 1000) + (minute * 60000) + (second * 1000) + millisecond; | |
| } | |
| function ts2parts(ts) { | |
| var f = Math.floor; | |
| var n = f(ts / 864e5) + 719162; | |
| var y400 = f(n / 146097); | |
| n -= y400 * 146097; | |
| var y100 = f(n / 36524); | |
| if (y100 == 4) y100 = 3; | |
| n -= y100 * 36524; | |
| var y4 = f(n / 1461); | |
| n -= y4 * 1461; | |
| var y1 = f(n / 365); | |
| if (y1 == 4) y1 = 3; | |
| n -= y1 * 365; | |
| var year = y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1; | |
| var leap = y1 == 3 && (y4 != 24 || y100 == 3); | |
| var days = leap ? d366 : d365; | |
| var month = n >> 5; | |
| while (n >= days[month + 1]) | |
| month++; | |
| var day = n - days[month] + 1; | |
| var hour = (Math.floor((ts % 864e5) / 36e5) + 24) % 24; | |
| var minute = (Math.floor((ts % 36e5) / 6e4) + 60) % 60; | |
| var second = (Math.floor((ts % 6e4) / 1e3) + 60) % 60; | |
| var millisecond = ((ts % 1e3) + 1e3) % 1e3; | |
| return [year, month, day, hour, minute, second, millisecond]; | |
| } | |
| function parts2ts_native(year, month, day, hour, minute, second, millisecond) { | |
| return Date.UTC(year, month, day, hour, minute, second, millisecond); | |
| } | |
| function ts2parts_native(ts) { | |
| var dt = new Date(ts); | |
| return [dt.getUTCFullYear(), dt.getUTCMonth(), dt.getUTCDate(), dt.getUTCHours(), dt.getUTCMinutes(), dt.getUTCSeconds(), dt.getUTCMilliseconds()]; | |
| } |
Some background: I'm considering writing a new date time library for JavaScript. This would be part of its core. The Date object has implementation quirks in various browsers, and while libraries like moment.js are worthy, they still suffer from implementation differences of the Date object.
Also - surprisingly - it's faster to compute these in script than it is with the native Date object. I'm not sure why, but that's what the jsperf tests show.
I'm also thinking about this with regard to moment.js
The "why is this faster" may be in part that I'm not handling underflow/overflow scenarios, and that I'm computing the values all at once in a single pass, rather than one part at a time.
Updated to fix floating point math errors, and errors with flooring negative values.
Updated again, apparently I botched the time parts of ts2parts. oops!
Perf Tests (updated):
http://jsperf.com/ts2parts/2
http://jsperf.com/parts2ts/4