DEV Community

Brad
Brad

Posted on

Python Time Tracker + Auto-Billing Script (Bye Toggl!)

Python Time Tracker + Auto-Billing Script (Bye Toggl!)

I cancelled my Toggl subscription last year and replaced it with 50 lines of Python. Here's the exact script, and how I extended it to auto-generate billing reports.

Why Toggl Isn't Worth $10/Month

Toggl is great software. But for solo freelancers, it's massive overkill. The core feature I needed:

  1. Start/stop timer
  2. Assign time to a client project
  3. See total hours per week/month
  4. Calculate billing amounts

That's 4 features. $10/month. Let's build it.

The Core Time Tracker

import sqlite3
import time
from datetime import datetime, date
from pathlib import Path

DB_PATH = Path.home() / ".time_tracker.db"

def init_db():
    conn = sqlite3.connect(DB_PATH)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS time_entries (
            id INTEGER PRIMARY KEY,
            project TEXT NOT NULL,
            description TEXT,
            start_time REAL NOT NULL,
            end_time REAL,
            duration_hours REAL,
            rate REAL DEFAULT 75
        )
    """)
    conn.commit()
    return conn

def start_timer(project, description="", rate=75):
    """Start tracking time for a project."""
    conn = init_db()
    start = time.time()
    conn.execute(
        "INSERT INTO time_entries (project, description, start_time, rate) VALUES (?, ?, ?, ?)",
        (project, description, start, rate)
    )
    conn.commit()
    entry_id = conn.execute("SELECT last_insert_rowid()").fetchone()[0]
    print(f"⏱ Timer started: {project} | ID: {entry_id}")
    return entry_id

def stop_timer(entry_id):
    """Stop timer and calculate duration."""
    conn = init_db()
    end = time.time()
    start = conn.execute("SELECT start_time, rate FROM time_entries WHERE id=?", 
                          (entry_id,)).fetchone()

    if not start:
        print(f"Entry {entry_id} not found")
        return

    duration = (end - start[0]) / 3600  # Convert to hours
    conn.execute(
        "UPDATE time_entries SET end_time=?, duration_hours=? WHERE id=?",
        (end, duration, entry_id)
    )
    conn.commit()
    print(f"✅ Stopped | Duration: {duration:.2f}h | Amount: ${duration * start[1]:.2f}")
    return duration
Enter fullscreen mode Exit fullscreen mode

Auto-Billing Report Generator

def generate_billing_report(client=None, month=None):
    """Generate a billing summary report."""
    conn = init_db()

    query = "SELECT project, description, duration_hours, rate FROM time_entries WHERE end_time IS NOT NULL"
    params = []

    if client:
        query += " AND project=?"
        params.append(client)

    if month:
        # Filter by month
        month_start = datetime(datetime.now().year, month, 1).timestamp()
        query += " AND start_time >= ?"
        params.append(month_start)

    entries = conn.execute(query, params).fetchall()

    if not entries:
        print("No entries found")
        return

    print(f"{'Project':<20} {'Description':<30} {'Hours':>6} {'Rate':>6} {'Amount':>10}")
    print("-" * 75)

    total_hours = 0
    total_amount = 0

    for project, desc, hours, rate in entries:
        amount = (hours or 0) * rate
        total_hours += (hours or 0)
        total_amount += amount
        print(f"{project:<20} {(desc or ''):<30} {(hours or 0):>6.2f} ${rate:>5} ${amount:>9.2f}")

    print("-" * 75)
    print(f"{'TOTAL':<52} {total_hours:>6.2f} {'':>6} ${total_amount:>9.2f}")

    return total_hours, total_amount

# Quick usage
entry_id = start_timer("Acme Corp", "API integration", rate=80)
# ... do your work ...
stop_timer(entry_id)

# Monthly report
generate_billing_report(client="Acme Corp", month=5)
Enter fullscreen mode Exit fullscreen mode

Usage Pattern

My typical workflow:

# Morning: start tracking
python tracker.py start "Acme Corp" "Sprint planning" --rate 80

# End of day: stop and review
python tracker.py stop 42
python tracker.py report --month 5

# Invoice time
python tracker.py invoice --client "Acme Corp" --month 5
Enter fullscreen mode Exit fullscreen mode

Extending It

I added these integrations over time:

  • Auto-generate PDF invoices from tracked hours
  • Export CSV for accountants
  • Weekly summary email to myself
  • Slack notifications for started/stopped timers

The Complete Freelancer Toolkit

This time tracker is one of 5 scripts I built to replace my SaaS stack:

  1. Time Tracker — this one (replaces Toggl $10/mo)
  2. Invoice Generator — generates PDFs + emails them (replaces Freshbooks $15/mo)
  3. Email Campaign Tool — client newsletters (replaces Mailchimp $20/mo)
  4. Proposal Generator — professional proposals (replaces Proposify $49/mo)
  5. Revenue Dashboard — monthly P&L overview

Total: ~$400/yr saved

All 5 scripts are available as a toolkit: Python Business Automation Toolkit — $9 one-time. Includes full source code, docs, and SQLite DB setup.


What tool would you build next? I'm thinking about a CRM replacement — track clients, notes, follow-ups — all in a local SQLite DB.

Top comments (0)