The Easiest Way to Add Time Intervals in JavaScript

Written by anwarhjg | Published 2024/01/13
Tech Story Tags: javascript | date-and-time-values | learn-javascript | mouth-breathing | workplace-timesheet | hackernoon-top-story | javascript-arrays | time-intervals-in-javascript

TLDRYou have a timesheet String, a hovering boss, and JavaScript. The Problem: You want to add the hours together and stop your boss hovering. The Solution: Does not require witchcraft. via the TL;DR App

Huuuff. A cold tightness worms its way down your spine.

Haaaaah. Your boss's frigid breath washes over your neck like an overflowing sewer. But you can’t tell them to hover somewhere else...they've been watching you like a hawk ever since the office time-tracking system broke.

Now, they're just there...hovering…breathing. Huffffff.

You tried writing your hours on a timesheet, but your boss is pretty busy with all that respiration. What if they didn't do the math right and mis-added your hours?

Here's how to take matters into your own hands with JavaScript. Haaaaa.

The Problem

You have a timesheet that looks like the contents of this String:

const a = `November 30 2023 13:20-15:00, 15:30-16:40
December 4 2023 15:45-16:15, 
December 5 2023 08:00-08:30, 18:15-19:30, 21:45-22:15, 22:30-23:00
December 6 2023 19:45-21:45 
December 7 2023 14:15-14:45, 15:15-15:45, 16:00-16:30, 16:45-17:15, 18:45-20:15, 20:45-22:45
December 13 2023 03:00-03:50
December 15 2023 09:00-09:30 20:30-21:15 21:45-22:30 23:30-24:00
December 16 2023 23:25-23:55
December 17 2023 19:05-19:50 20:30-21:30 22:15-23:45
December 20 2023 23:30-24:00
December 21 2023 02:20-2:50 03:15-03:30 13:40-14:00 16:00-17:15 17:45-18:45 19:20-20:10 21:30-22:20   23:00 - 24:00
December 22 2023 0:00-0:15`;

Each line contains a date followed by some time intervals. But they're not very cleanly written — some intervals are comma-separated, others have irregular spacing, etc.

Given these inconsistencies, it's probably good to assume no other guarantees. For instance, who says all the times will be from the same year? Nobody, that’s who. You want to add the hours together as robustly as possible.

The Solution

This is pretty easy. We start by creating a couple of regular expressions and a helper function. Then, we’ll just…Huuuuffh!

Ugh!! Boss, go chill somewhere for a second!

As I was saying, now we can complete the task with a three-step algorithm:

  1. We split the timesheet string into individual lines and reduce over them to create an array of objects

  2. For each iteration, we:

    A. Split the line around the year using yearRegex, recording the date string

    B. Collect all time range intervals using intervalsRegex

    C. Reduce over the time ranges, parsing each as a JavaScript Date object using the parseDate helper and the date string from step 2.A

  3. Reduce over the array of objects to find the total hours

const yearRegex = /(\d{4})/gi;
const intervalsRegex = /(\d+\:\d+)\s*-\s*(\d+\:\d+)/gi;
const parseDate = (date, time) => Date.parse(`${date} ${time}`);

let times = [...a.split("\n")].reduce((arr, entryLine) => {
  let entryLineSplit = entryLine.split(yearRegex); 
  let o = {
    date: entryLineSplit[0] + entryLineSplit[1],
    timeRanges: [...entryLine.matchAll(intervalsRegex)],
  };
  o.hoursForDay = o.timeRanges.reduce((total, [x, start, end]) => {
    let s = parseDate(o.date, start);
    let e = parseDate(o.date, end);
    return total + (e - s) / 1000 / 60 / 60;
  }, 0);
  return [...arr, o];
}, []);
console.log(times);
let totalHours =  times.reduce((total, { hoursForDay }) => total + hoursForDay, 0);
console.log(totalHours);

If you uncomment the console.log(times); statement, you'll see an array containing objects like:

  {
    date: 'November 30 2023',
    timeRanges: [
      [
        '13:20-15:00',
        '13:20',
        '15:00',
        index: 17,
        input: 'November 30 2023 13:20-15:00, 15:30-16:40',
        groups: undefined
      ],
      [
        '15:30-16:40',
        '15:30',
        '16:40',
        index: 30,
        input: 'November 30 2023 13:20-15:00, 15:30-16:40',
        groups: undefined
      ]
    ],
    totalHours: 2.8333333333333335
  },

The Benefits of This Method

Building an array of objects has a few distinct advantages over simply extracting the time intervals and adding them.

  • It makes for easy traversal after the fact. This is ideal if you want to do something like graph your daily times.

  • Saving the date string for each record allows the use of built-in JS date arithmetic methods following a call to Date.parse.

  • The object is a convenient place to store the results of calling String.prototype.split, which might not be unique depending on whether two days included the same time intervals.

Disadvantages of This Method

This solution isn't perfect:

  • It requires two big traversals — once over the result of splitting the timesheet, and then once over the times object. To optimize this code, it’d likely be better to use a single reduce over an empty object containing totalHours and times as fields.

  • It uses regular expressions that might get more complicated with a more complex format

Wrapping Up

You now know how to extract time from a messy timesheet. With a little extra effort, you could even build a full-on time clock. But then you wouldn't get to spend all that nice quality time getting to know your boss, would you? Huffff.


Written by anwarhjg | I'm a witch IRL. Not a wizard — that's for the KKK.
Published by HackerNoon on 2024/01/13