Can I check if event happened during an hour, regardless of date? Moment.js

Viewed 252

I'm tracking the usage of a device, and showing users their usage trends by hour. Basically, I need to look through times documents and see if the device was "on" betwen 6pm and 7pm, then 7pm and 8pm, the 8pm and 9pm, and so on for all 24 hours.

This is what I originally wrote:

      // loop through 24 hours of the day
      for (let j = 0; j < 24; j++) {
        const beginningOfHour = moment().startOf('day').add(j, 'hour').toDate()
        const endOfHour = moment(beginningOfHour).add({ m: 59, s: 59, ms: 999 }).toDate()

        const cumulativeHours = timePerPeriod(beginningOfHour, endOfHour, myTimes)  // calculation func

        trendsArray.push(cumulativeHours)
      }

This doesn't work becasue beginningOfHour and endOfHour also have a date attached to them.

I can't figure out how to check my times documents for just the hour portion, without any reference to date. Any advice on how to do this?

EDIT: Here is what a times document looks like:

_id: 5e56cf9ae65bf2b30a6ab525  // ObjectID type
user_id: 5e56bb2b40ad526200401773  // ObjectID type
start: 2020-02-27T00:00:00.000+00:00  // Date type
stop: 2020-02-27T06:00:00.000+00:00  // Date type

The device can be on for any length of time, like 3 months straight or 15 seconds. Each time document is examined, and if it is on for any length of time during that hour duration, the length in miliseconds that it was on during that hour period is returned by my calculation function (called cumulativeHours above).

2 Answers

You can iterate through the times and filter by the hour of day and/or minute of the timestamp by using the .hour() or the .minute() methods on the moment objects like this ( for simplicity reasons i only check the hour):

let sampleArrayOfDateTimes = [
  moment("2013-02-08 08:59"),
  moment("2013-02-08 09:00"),
  moment("2013-02-08 09:30"),
  moment("2013-02-08 10:00")
]

// find datetimes between 09:00 (including) and 10:00 (excluding)

let arrayWithTimesBetween9and10 = sampleArrayOfDateTimes.filter(datetime => datetime.hour() == 9);

console.log("the following datetimes are between 09:00 and 09:59");
arrayWithTimesBetween9and10.forEach(datetime => {
  console.log(datetime.format());
});
<script src="https://unpkg.com/moment@2.24.0/moment.js"></script>

As the question was edited and is now asking for time ranges overlapping each other here comes a solution for the edited version. This is a very simplified approach, which doesn't take into account minutes or timespans over multiple days, but it hope it conveys the idea. Basically for every timespan-combination all 4 possibilites need to be checked (timespans overlap fully, do not overlap at all or only start or only end time is in between):

let sampleDatetimeRanges = [
  {
    start: moment("2013-02-08 09:00"),
    end: moment("2013-02-08 10:00")
  },
  {
    start: moment("2013-02-08 08:00"),
    end: moment("2013-02-08 12:00")
  },
  {
    start: moment("2013-02-08 13:00"),
    end: moment("2013-02-08 18:00")
  } 
];

function isBetweenHours(start, end, hourInQuestion) {
  return start <= hourInQuestion && end >= hourInQuestion;
}


// calculate the timespan between 09:00 and 10:00
const rangeStart = 9;
const rangeEnd = 11;
const hoursCount = sampleDatetimeRanges.map(current => {
  let startHour = current.start.hour();
  let endHour = current.end.hour();
  if (startHour <= rangeStart && endHour >= rangeEnd) { // full time covered
    return rangeEnd - rangeStart;
  } else if (startHour <= rangeStart && isBetweenHours(rangeStart, rangeEnd, endHour)) { // only end time in timespan
    return endHour - rangeStart;
  } else if (isBetweenHours(rangeStart, rangeEnd, startHour) && endHour >= rangeEnd) { // only start time in timespan
    return rangeEnd - startHour;
  } else if (isBetweenHours(rangeStart, rangeEnd, startHour) && isBetweenHours(rangeStart, rangeEnd, endHour)) {
    return endHour - startHour;
  }
  // not in timespan
  return 0;

}).reduce((sum, current) => sum + current, 0)

console.log(`hours covered in the timespan from ${rangeStart} to ${rangeEnd}: ${hoursCount}. `);
<script src="https://unpkg.com/moment@2.24.0/moment.js"></script>

Related