Migrating from Harvest to Org mode for time tracking

I've set myself a challenge of migrating from Harvest to Org mode for the purposes of tracking time and ensuring projects don't go over budget.

This is still a work in progress and I haven't yet got a solution to give me a percentage of budget used based on the time spent, maybe a task for next week! I have however spent a little time on getting past projects into Org mode.

I have a single file in Org mode which lists all current projects - using the hierarchy client / project / project components. Project components are things such as iOS Development, Android Development, Project Management, Bug Fixing, Planning, etc. I then clock in and out of the project components to record my time.

For new projects this is working well, but for projects which were on pause and now ready to continue (which happens all too often) I want to import my current logged time from Harvest into my Org file.

Harvest can export a detailed time breakdown into a CSV file. My plan is to export each project into its own CSV file and then run a Python script to convert the data into something I can add into my Org file.

Here is an example of a CSV file exported by Harvest:

Date,Client,Project,Project Code,Task,Notes,Hours,Hours Rounded,Billable?,Invoiced?,First Name,Last Name,Roles,Employee?,Billable Rate,Billable Amount,Cost Rate,Cost Amount,Currency,External Reference URL
2019-11-18,Client 1,Mapping App Map Pin Nov 2019 updates,"",Planning,,0.16,0.2,Yes,No,Matthew,Kennard,,Yes,43.33,8.666,0.0,0.0,British Pound - GBP,
2019-11-19,Client 1,Mapping App Map Pin Nov 2019 updates,"",iOS Development,,1.92,2.0,Yes,No,Matthew,Kennard,,Yes,43.33,86.66,0.0,0.0,British Pound - GBP,
2019-11-19,Client 1,Mapping App Map Pin Nov 2019 updates,"",Android Development,,1.59,1.6,Yes,No,Matthew,Kennard,,Yes,43.33,69.328,0.0,0.0,British Pound - GBP,
2019-11-20,Client 1,Mapping App Map Pin Nov 2019 updates,"",Android Development,,2.19,2.2,Yes,No,Matthew,Kennard,,Yes,43.33,95.326,0.0,0.0,British Pound - GBP,

Harvest doesn't seem to provide a way of giving you a start and end time for a task, so I'm going to assume a day starts at 9am and then I work continuously on my logged tasks.

Here is my quick Python script to convert the CSV file into Org mode:

import sys
import csv
import re
import datetime
from datetime import date, datetime, time, timedelta

def hours_minutes(td):
    return td.seconds // 3600, (td.seconds // 60) % 60

def construct_log_line(task_date, hours, start_time):
    year, month, day = task_date.split('-')
    start_date = datetime.combine(date(int(year), int(month), int(day)), start_time)
    end_date = start_date + timedelta(hours=hours)
    length_hours, length_minutes = hours_minutes(end_date - start_date)
    log_line = "CLOCK: [%s %02d:%02d]--[%s %02d:%02d] => %02d:%02d" % (
        task_date,
        start_date.hour,
        start_date.minute,
        task_date,
        end_date.hour,
        end_date.minute,
        length_hours,
        length_minutes)
    return log_line, (end_date + timedelta(minutes=1)).time()

filename = sys.argv[1]

client = None
project = None
tasks = {}
days_end_times = {}

with open(filename) as csvfile:
    reader = csv.reader(csvfile, delimiter=',', quotechar='"')
    for row in reader:
        if not re.search("^[0-9]{4}", row[0]):
            continue
        (task_date, client, project, project_code, task, hours, hours_rounded, *rest) = row
        log_lines = tasks.get(task, [])
        if hours == "":
            hours = hours_rounded
        log_line, end_time = construct_log_line(task_date, float(hours), days_end_times.get(task_date, time(9, 0, 0)))
        days_end_times[task_date] = end_time
        log_lines.append(log_line)
        tasks[task] = log_lines

print(f"** {client}")
print(f"*** {project}")
for task_name, log_lines in tasks.items():
    print(f"**** {task_name}")
    print(":LOGBOOK:")
    for log_line in log_lines:
        print(log_line)
    print(":END:")

Output from the script using the above CSV file:

** Client 1
*** Mapping App Map Pin Nov 2019 updates
**** Planning
:LOGBOOK:
CLOCK: [2019-11-18 09:00]--[2019-11-18 09:09] => 00:09
:END:
**** iOS Development
:LOGBOOK:
CLOCK: [2019-11-19 09:00]--[2019-11-19 10:55] => 01:55
:END:
**** Android Development
:LOGBOOK:
CLOCK: [2019-11-19 10:56]--[2019-11-19 12:31] => 01:35
CLOCK: [2019-11-20 09:00]--[2019-11-20 11:11] => 02:11
:END:

I can now paste this into my time tracking file and continue to log work I do on this project.