coding

Tracking my working hours on personal projects using Node.js

Finding out the hard way that some information are not supposed to be known

Written in June 16, 2024 - 🕒 5 min. read

illustration of how it feels to work with foss
illustration of how it feels to work with foss

As a developer fully committed (pun intended, and not the only one) in FOSS side projects, I often lose track of time. It feels like I’ve spent countless hours coding, but how many exactly? Curiosity got the best of me, so I decided to write a Node.js script to find out. Spoiler: I immediately regretted this decision after seeing just how much of my free time was spent coding. Here’s the story.

Drafting the plan

I wanted a script that could calculate my working hours based on my GIT commits. Since I’m an avid believer of the atomic commits conventions, the idea is simple: when I’m working on my side projects, I’m committing. If there’s a gap of more than 3 hours between commits it means I’m probably off doing something else, like eating, sleeping, or watching programming videos (no wait).

Choosing the right package

There are many GIT libraries for Node.js, but I went with simple-git for its ease of use. It’s a wrapper around GIT commands, making it perfect for this task.

So after installing simple-git, and doing npm init and all of these shenanigans, I was ready to start coding.

The code

Ok, let’s first get familiarized with simple-git, here is a simple code to fetch the commit log:

const simpleGIT = require('simple-git');
const git = simpleGIT();

async function getCommitLog() {
    try {
        const log = await git.log();
        return log.all;
    } catch (error) {
        console.error('Error fetching commit log:', error);
    }
}

getCommitLog().then(commits => console.log(commits));

With the commit log in hand, let’s ”apply” our drafted plan into code and calculate the work hours. The idea is to iterate through the commits, and whenever there’s a gap of more than 3 hours between two commits, consider the previous commit as the end of a work session.

So for example, if I start working at 9 AM and commit at 10 AM, then commit again at 3 PM, the script should consider the work session to be from 9 AM to 10 AM, so 1 hour.

async function calculateWorkHours() {
    try {
        const commits = await getCommitLog();

        if (commits.length === 0) {
            console.log('No commits found in this repository.');
            return;
        }

        let totalWorkTime = 0;
        let currentCommit = commits[0];
        const maxInterval = 3 * (60 * 60 * 1000); // 3 hours in milliseconds

        for (let i = 1; i < commits.length; i++) {
            const nextCommit = commits[i];
            const currentCommitTime = new Date(currentCommit.date).getTime();
            const nextCommitTime = new Date(nextCommit.date).getTime();

            if ((currentCommitTime - nextCommitTime) > maxInterval) {
                totalWorkTime += currentCommitTime - new Date(commits[i - 1].date).getTime();
                currentCommit = nextCommit;
            }
        }

        totalWorkTime += new Date(currentCommit.date).getTime() - new Date(commits[commits.length - 1].date).getTime();
        const totalWorkHours = totalWorkTime / (1000 * 60 * 60);

        console.log(`Total work hours: ${totalWorkHours.toFixed(2)} hours`);
    } catch (error) {
        console.error('Error calculating work hours:', error);
    }
}

calculateWorkHours();

That’s basically it, but since we’re here, why not squeeze some more information? Not that knowing the total hours isn’t enough, but now I want to know how much time, on average, I am, uh, wasting—uh, I mean, having some quality time with my laptop.

Let’s add that calculation:

async function calculateWorkHours() {
    try {
        const commits = await getCommitLog();

        if (commits.length === 0) {
            console.log('No commits found in this repository.');
            return;
        }

        let totalWorkTime = 0;
        let currentCommit = commits[0];
        const maxInterval = 3 * (60 * 60 * 1000); // 3 hours in milliseconds

        for (let i = 1; i < commits.length; i++) {
            const nextCommit = commits[i];
            const currentCommitTime = new Date(currentCommit.date).getTime();
            const nextCommitTime = new Date(nextCommit.date).getTime();

            if ((currentCommitTime - nextCommitTime) > maxInterval) {
                totalWorkTime += currentCommitTime - new Date(commits[i - 1].date).getTime();
                currentCommit = nextCommit;
            }
        }

        totalWorkTime += new Date(currentCommit.date).getTime() - new Date(commits[commits.length - 1].date).getTime();
        const totalWorkHours = totalWorkTime / (1000 * 60 * 60);

        const firstCommitTime = new Date(commits[commits.length - 1].date).getTime();
        const lastCommitTime = new Date(commits[0].date).getTime();
        const totalDays = (lastCommitTime - firstCommitTime) / (1000 * 60 * 60 * 24);

        const averageHoursPerDay = totalWorkHours / totalDays;

        console.log(`Total work hours: ${totalWorkHours.toFixed(2)} hours`);
        console.log(`Average hours per day: ${averageHoursPerDay.toFixed(2)} hours`);
    } catch (error) {
        console.error('Error calculating work hours:', error);
    }
}

calculateWorkHours();

Let’s put it to practice

After running the script on my latest side project, which I might write a blog post about soon, I was greeted with the following output:

$ node scripts/calculateWorkHours.js 
Total work hours: 98.77 hours
Average hours per day: 3.74 hours

Excuse me, what? 98.77 hours? That’s almost 100 hours spent on a side project in a month. And 3.74 hours per day? I mean, I knew I was spending a lot of time on my side projects, but seeing the numbers was a bit of a shock.

If people ask me, I say I’m quite an active person, after all, I do springboard diving 3 times a week, for a total of 4 hours per week, plus the gym sessions, around a total of 6 hours per week. So, yeah, a total of 10 hours per week, or 1.42 hours per day, not even close to the 3.74 hours per day I’m spending on my side projects.

dissapointed but not surprised
dissapointed but not surprised

Caveats

While this script is nifty, it’s not without its flaws:

  • Assumptions on Breaks: It assumes any period longer than 3 hours between commits is a break. This might not always be true, but it’s a good enough approximation.
  • Commit Habits: If you’re someone who forgets to commit frequently, the script’s accuracy plummets.
  • Timezone Differences: Commits made in different time zones can mess with the calculations.
  • Figuring out how much time you’re wasting: This one is a bit subjective, I guess, but in my case, oof, I was not ready for that number.

Conclusion

Writing this script was enlightening and horrifying all at once. I now have concrete proof of the absurd number of hours I spend on my side projects. If you’re curious (or crazy) enough to ”bisect” your programming habits, it can be quite a “fun” exercise.

And remember, while tracking your productivity is great, sometimes ignorance is bliss because after seeing my total hours, I just wanted to curl up and play some of my backlog games to compensate for all that lost free time.

Happy coding, and happy atomic commits!

Tags:


Post a comment

Comments

No comments yet.