I would to compute index into an array from millisecond (epoch) timestamp. The array is 167 long, each index is hour in week (i.e. index 0
points to 0:00 on Monday, 24
to 0:00 on Tuesday, 28
to 4:00 Tuesday, ...). I came to this solution, which works:
function getIndex(timestamp) {
const hoursInDay = 24;
const date = new Date(timestamp);
const dayIndex = (date.getUTCDay() + 6) % 7; // index from Monday
const hourIndex = date.getUTCHours();
return dayIndex * hoursInDay + hourIndex;
}
The problem is that this is quite slow. We have few thousands of these timestamps and very limited time to process them.
Is there maybe a purely numerical way to achieve the same effect, so that we don't have to construct and use Date
each time?
As you are working with UTC datetimes there is no complexity that relates to timezones, and we can avoid creating a Date instance.
This function returns the same values as yours:
const HOUR = 3600000;
const DAY = 24;
const THREE_DAYS = 3 * DAY;
const WEEK = 7 * DAY;
const getIndex = timestamp => ((timestamp / HOUR | 0) + THREE_DAYS) % WEEK;
In my tests this function executes more than 10 times faster than the original one.
Here is how I tested and measured. Note that I moved the first const
declaration out of your function, as it is a waste of time to evaluate that with each call:
// Original code (with one obvious optimisation)
const hoursInDay = 24;
function getIndex(timestamp) {
const date = new Date(timestamp);
const dayIndex = (date.getUTCDay() + 6) % 7; // index from Monday
const hourIndex = date.getUTCHours();
return dayIndex * hoursInDay + hourIndex;
}
// Proposed improvement
const HOUR = 3600000;
const DAY = 24;
const THREE_DAYS = 3 * DAY;
const WEEK = 7 * DAY;
const getIndex2 = timestamp => ((timestamp / HOUR | 0) + THREE_DAYS) % WEEK;
// Verify that both functions return the same values
const addTime = 2727359; // Some arbitrary slice of time (~31.5 days)
const n = 1000000 * addTime;
for (let timestamp = 0; timestamp < n; timestamp += addTime) {
let a = getIndex(timestamp);
let b = getIndex2(timestamp);
if (a !== b) throw "functions return a different result for timestamp " + timestamp;
}
// Perform time measurements
let time1 = 0, time2 = 0, start;
for (let repeat = 1; repeat < 10; repeat++) {
start = performance.now();
for (let timestamp = 0; timestamp < n; timestamp += addTime) {
getIndex(timestamp);
}
time1 += performance.now() - start;
start = performance.now();
for (let timestamp = 0; timestamp < n; timestamp += addTime) {
getIndex2(timestamp);
}
time2 += performance.now() - start;
}
console.log("speed up factor", time1 / time2);