Skip to content

Instantly share code, notes, and snippets.

@thelibrarian
Last active April 23, 2016 06:01
Show Gist options
  • Save thelibrarian/06a86060f623d0fbe9394e30b6cbe4df to your computer and use it in GitHub Desktop.
Save thelibrarian/06a86060f623d0fbe9394e30b6cbe4df to your computer and use it in GitHub Desktop.
Time Tracker.app to org-mode Converter
#!/usr/bin/env ruby
#
# Converts a Time Tracker.app <https://github.com/rburgst/time-tracker-mac> CSV export
# to org-mode clock entries.
#
# Simply call like so:
# ./tt_to_org.rb Time\ Tracker\ Data.csv
#
# This will output an Org file in the same directory, with same name
# as the input file, but with a ".org" extension.
#
# Each Project will be a top-level headline, and each task will be
# a second-level headline under its project's headline. The time
# entries will be entered under its task headline in reverse order,
# to match org-mode's behaviour.
#
# NOTE: this does not do any real error checking other than to make
# sure you supplied one argument. It assumes that you are giving it
# a valid Time Tracker CSV file.
#
# LICENSE
#
# Copyright (c) 2016 Tony Kemp
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
require 'csv'
require 'time'
@entries = {}
def to_clock_entry(start, finish)
s = Time.parse(start)
f = Time.parse(finish)
orgfmt = "[%Y-%m-%d %a %H:%M]"
mins = ((f - s) / 60.0).round(0)
hrs = mins / 60
mins = mins % 60
return "CLOCK: #{s.strftime(orgfmt)}--#{f.strftime(orgfmt)} => #{hrs}:#{format("%02d", mins)}"
end
def create_structure(project, task)
if @entries[project].nil?
@entries[project] = Hash.new
end
if @entries[project][task].nil?
@entries[project][task] = Array.new
end
end
unless ARGV[0].nil?
data = CSV.read(ARGV[0], headers: true)
data.each do |row|
create_structure(row["Project"], row["Task"])
@entries[row["Project"]][row["Task"]] << to_clock_entry(row["Start"], row["End"])
end
File.open(File.basename(ARGV[0], ".csv") + ".org", "w") do |file|
@entries.each_key do |project|
file.puts("* #{project}")
@entries[project].each_key do |task|
file.print("** #{task}\n:LOGBOOK:\n")
# Org logs clock entries with the newest at the top
@entries[project][task].reverse.each do |entry|
file.puts(entry)
end
file.print(":END:\n\n")
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment