Download from here -- likely this will be a newer version if I fix any bugs in the version below.
Install this script in your TaskPaper scripts directory (~/Library/Application Support/TaskPaper/Scripts) and assign it a shortcut in System Preferences.
When called for the first time, it will add a note to the selected task (or the first task under the selected project) of the form to clock in:
CLOCK: [yyyy-mm-dd DDD hh:mm]
Subsequently, whenever you call the script it will look for the first line of the format above, and if found append the current time to clock out with the line changed to look like this:
CLOCK: [yyyy-mm-dd DDD hh:mm]--[yyyy-mm-dd DDD hh:mm] => HH:MM
Where the last part of the line HH:MM is the difference between the two timestamps it follows.
If you want to see how much time you've spent clocked in so far, simply clock out and after looking at the time, undo the change.
If there is no unfinished clock in, then the script clocks in to the selected task as above, so you can log in and out by pressing the shortcut key you assign to the script repeatedly.
I already have some elisp that runs under emacs org-mode that builds an inline MultiMarkDown table of weekly hours by adding up the relevant clock lines. But you could easily write a script to search for CLOCK lines and add up those times to generate a report.
property clockString : "CLOCK: "
-- return a timestamp string from a date object
on dateToTimestamp(theDate)
set {weekday:w, day:d, year:y, time:t} to theDate
set theTime to time string of theDate
-- Calculate the month number.
copy theDate to b
set b's month to January
set m to (b - 2500000 - theDate) div -2500000
-- Timestamp in "yyyy-mm-dd DDD www hh:mm" format.
tell theTime
set shortTime to text 1 thru 5
end tell
tell w as string
set shortDay to text 1 thru 3
end tell
tell (y * 10000 + m * 100 + d) as string
set dateString to text 1 thru 4 & "-" & text 5 thru 6 & "-" & text 7 thru 8 & " " & shortDay & " " & shortTime
end tell
return dateString
end dateToTimestamp
-- return a date object from a timestamp string
on timestampToDate(theTimestamp)
set theDate to date ("1/1/1000" as string)
tell theTimestamp
set theDate's year to text 1 thru 4
set theDate's month to text 6 thru 7
set theDate's day to text 9 thru 10
set theDate's time to (text 16 thru 17) * hours + (text 19 thru 20) * minutes
end tell
return theDate
end timestampToDate
-- calculate the difference between the two timestamps in a clock string
-- "CLOCK: [begin-timestamp]--[end-timestamp]"
on getElapsedTime(clockString)
set elapsedString to ""
tell clockString
set beginDate to my timestampToDate(text 9 thru 28)
set endDate to my timestampToDate(text 33 thru 52)
end tell
set deltaDate to endDate - beginDate
set deltaHours to deltaDate div hours
set deltaMinutes to (deltaDate mod hours) div minutes
if deltaHours < 10 then
set elapsedString to elapsedString & " "
end if
set elapsedString to elapsedString & deltaHours & ":"
if deltaMinutes < 10 then
set elapsedString to elapsedString & "0"
end if
set elapsedString to elapsedString & deltaMinutes
return elapsedString
end getElapsedTime
set theDate to dateToTimestamp(current date)
tell front document of application "TaskPaper"
set thisTask to get selected entry
set clock to clockString & "[" & theDate & "]"
set clocks to search with query (clockString & " and type = note")
set clockout to false
set runningClocks to {}
-- make sure we have a task selected
if entry type of thisTask is note type then
set thisTask to container of selected entry
else if entry type of thisTask is project type then
set projectTasks to entire contents of selected entry
set thisTask to item 1 of projectTasks
end if
-- look for a running clock (clocked in but not clocked out) and clock out if we find one
repeat with each in clocks
set theContent to text content of each
if entry type of each is note type and theContent begins with (clockString & "[") and theContent does not contain "]--[" then
if clockout is false then
set clockout to true
tell each
set theContent to text content & "--[" & theDate & "] => "
set text content to theContent & my getElapsedTime(theContent)
end tell
end if
end if
end repeat
-- if we didn't find anything to clock out of, then clock in to the current task
if clockout is false then
tell thisTask
make new note with properties {text content:clock}
end tell
end if
end tell
(*
Copyright (c) 2010 Gary V. Vaughan <gary@vaughan.pe>
This script is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This script is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*)