javascriptalgorithmperformance

Computing index from timestamp


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?


Solution

  • 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);