Skip to content

Instantly share code, notes, and snippets.

@mattjohnsonpint
Last active June 25, 2017 00:45
Show Gist options
  • Select an option

  • Save mattjohnsonpint/f6aa5e8b8aa040f65ae1 to your computer and use it in GitHub Desktop.

Select an option

Save mattjohnsonpint/f6aa5e8b8aa040f65ae1 to your computer and use it in GitHub Desktop.
JS replacement functions for timestamp <==> date parts without using the Date object
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()];
}
@mattjohnsonpint
Copy link
Copy Markdown
Author

@mattjohnsonpint
Copy link
Copy Markdown
Author

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.

@mattjohnsonpint
Copy link
Copy Markdown
Author

I'm also thinking about this with regard to moment.js

@mattjohnsonpint
Copy link
Copy Markdown
Author

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.

@mattjohnsonpint
Copy link
Copy Markdown
Author

Updated to fix floating point math errors, and errors with flooring negative values.

@mattjohnsonpint
Copy link
Copy Markdown
Author

mattjohnsonpint commented Jun 25, 2017

Updated again, apparently I botched the time parts of ts2parts. oops!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment