Super Simple Time Tracker Monthly Report

Hey guys,

I’m using obsidian for work and tracking the time for different tasks with the super simple time tracker plugin.
In order to not get distracted after a month I’m getting a report each month and I just wanted to showcase the dataviewjs query I got while using LLM:

// get the time tracker plugin api instance
let api = dv.app.plugins.plugins["simple-time-tracker"].api;

let dailyDurations = {};
let startDate = moment("01.10.2024", "DD.MM.YYYY"); // Startdatum
let endDate = moment("31.10.2024", "DD.MM.YYYY"); // Enddatum
let totalDuration = 0;

for (let page of dv.pages()) {
    // Überprüfe, ob der Dateiname ein Datum enthält (z.B. 01.10.24)
    let dateStr = page.file.name.split(".")[0] + "." + page.file.name.split(".")[1];
    let fileDate = moment(dateStr, "DD.MM.YY"); // Datei-Datum als Moment-Objekt
    
    // Prüfe, ob das Datum im gewünschten Zeitraum liegt
    if (fileDate.isBetween(startDate, endDate, null, '[]')) {
        // load trackers in the file with the given path
        let trackers = await api.loadAllTrackers(page.file.path);

        for (let { section, tracker } of trackers) {
            // Überprüfe, ob die tracker.entries-Eigenschaft definiert ist
            if (tracker.entries) {
                // Summiere die Dauer der Tracker für jeden Tag
                let day = dateStr;
                let duration = api.getTotalDuration(tracker.entries);
                if (dailyDurations[day]) {
                    dailyDurations[day] += duration;
                } else {
                    dailyDurations[day] = duration;
                }
                totalDuration += duration;
            }
        }
    }
}

// Sortiere die Tage nach dem Titel der Notiz
let sortedDays = Object.keys(dailyDurations).sort((a, b) => moment(a, "DD.MM.YY").diff(moment(b, "DD.MM.YY")));

// Erstelle die Markdown-Tabelle
let output = "| Datum | Dauer |\n";
output += "| --- | --- |\n"; // Tabellenkopf

for (let day of sortedDays) {
    output += `| ${day} | ${api.formatDuration(dailyDurations[day])} |\n`;
}

output += `| **Gesamt** | **${api.formatDuration(totalDuration)}** |\n`;

dv.el("div", output);


In the end it looks like this:

It’s still expandable but I like the simplicity and yet the versatility in it.

Have a great day

2 Likes

Since this might be of interest for somebody: I extended my query and the table with the summary of the overtime each day with a regular working time of 7 hours.

The whole thing looks like this in the end:

I included a line break between each week for the sake of better readability.

// get the time tracker plugin api instance
let api = dv.app.plugins.plugins["simple-time-tracker"].api;

let dailyDurations = {};
let startDate = moment("01.09.2024", "DD.MM.YYYY"); // Startdatum
let endDate = moment("30.09.2024", "DD.MM.YYYY"); // Enddatum
let totalDuration = 0;
let totalOvertime = moment.duration(0);

for (let page of dv.pages()) {
    // Überprüfe, ob der Dateiname ein Datum enthält (z.B. 01.10.24)
    let dateStr = page.file.name.split(".")[0] + "." + page.file.name.split(".")[1];
    let fileDate = moment(dateStr, "DD.MM.YY"); // Datei-Datum als Moment-Objekt
    
    // Prüfe, ob das Datum im gewünschten Zeitraum liegt
    if (fileDate.isBetween(startDate, endDate, null, '[]')) {
        // load trackers in the file with the given path
        let trackers = await api.loadAllTrackers(page.file.path);

        for (let { section, tracker } of trackers) {
            // Überprüfe, ob die tracker.entries-Eigenschaft definiert ist
            if (tracker.entries) {
                // Summiere die Dauer der Tracker für jeden Tag
                let day = dateStr;
                let duration = api.getTotalDuration(tracker.entries);
                if (dailyDurations[day]) {
                    dailyDurations[day] += duration;
                } else {
                    dailyDurations[day] = duration;
                }
                totalDuration += duration;
            }
        }
    }
}

// Berechne die Überstunden für jeden Tag
let normalWorkHours = moment.duration(7, 'hours');
for (let day in dailyDurations) {
    let fileDate = moment(day, "DD.MM.YY");
    if (fileDate.day() !== 0 && fileDate.day() !== 6) { // 0 = Sonntag, 6 = Samstag
        let overtime = moment.duration(dailyDurations[day]) - normalWorkHours;
        dailyDurations[day] = {
            duration: dailyDurations[day],
            overtime: overtime
        };
        totalOvertime.add(overtime);
    } else {
        dailyDurations[day] = {
            duration: dailyDurations[day],
            overtime: moment.duration(0)
        };
    }
}

// Sortiere die Tage nach dem Titel der Notiz
let sortedDays = Object.keys(dailyDurations).sort((a, b) => moment(a, "DD.MM.YY").diff(moment(b, "DD.MM.YY")));

// Erstelle die Markdown-Tabelle
let output = "| Wochentag | Datum | Dauer | Überstunden |\n";
output += "| --- | --- | --- | --- |\n"; // Tabellenkopf

let lastWeek = null;
for (let day of sortedDays) {
    // Erstelle einen Link im Format [[DD.MM.YY]] für das Datum
    let dayFormatted = moment(day, "DD.MM.YY").format("DD.MM.YY");
    let dayLink = `[[${dayFormatted}]]`;
    let dayOfWeek = moment(day, "DD.MM.YY").format("dddd");
    let overtime = dailyDurations[day].overtime;
    let hours = Math.floor(overtime / 3600000);
    let minutes = Math.floor((overtime % 3600000) / 60000);
    let overtimeStr = `${hours}:${minutes.toString().padStart(2, '0')}`;
    if (overtime < 0) {
        overtimeStr = `- ${overtimeStr}`;
    }
    
    // Überprüfe, ob eine neue Woche beginnt
    let currentWeek = moment(day, "DD.MM.YY").week();
    if (lastWeek !== null && currentWeek !== lastWeek) {
        output += "| --- | --- | --- | --- |\n";
    }
    lastWeek = currentWeek;
    
    output += `| ${dayOfWeek} | ${dayLink} | ${api.formatDuration(dailyDurations[day].duration)} | ${overtimeStr} |\n`;
}

output += `| **--** | **--** | **${api.formatDuration(totalDuration)}** | **${api.formatDuration(totalOvertime)}** |\n`;

dv.el("div", output);

Maybe somebody has an idea for improvement but right now I am pretty happy and it is working fine with a template using templater