I don’t find myself using the clock-in and clock-out features of org agenda. But I do want to use the CLOCK: property for tracking hours for contracted projects. Most of my time tracking is done after the fact, so I wanted a way to quickly add hours to tasks and also keep track of the dates I did the work.

I originally thought of just using the effort property to track hours worked, but I decided that there may be a day when I want to use effort tracking to decide priorities. Plus there isn’t date tracking with the effort property.

For now, I’ve created a function that prompts the user for a date and number of hours and automatically adds a clocked time range for those hours.

It even works if you choose a time to start in the date selection, so you can still select the appropriate time of day when you started working.

There is a known bug with Daylight Savings where the time stamps will be off by an hour if DST is active, but that’s a minor issue.

(defun my/prompt-for-clock-hours (date hours)
    (interactive (list (org-read-date) (read-number "Hours: ")))
    (let* ((marker (or (org-get-at-bol 'org-marker)
                     (org-agenda-new-marker)))
            (buffer (marker-buffer marker)))
      (org-with-remote-undo buffer
        (with-current-buffer buffer
      (save-excursion
        (let* ((log-start (org-log-beginning t))
                (d (org-parse-time-string date))
                (ts (encode-time d))
                (te (encode-time (modify-element-in-list 2 (+ hours (nth 2 d)) d))))
          (goto-char log-start)
          (insert "CLOCK:")
          (org-insert-time-stamp ts 'with-hm 'inactive)
          (insert "--")
          (org-insert-time-stamp te 'with-hm 'inactive)
          (save-excursion
            (insert "\n"))
          (org-ctrl-c-ctrl-c)))))))

There is a convenience function I wrote for modifying a list in emacs-lisp in place. It just loops over every element and if we hit the right index change the value. It’s not very efficient, but fast enough for small lists. It’s not really useful for big lists anyway

(defun modify-element-in-list (elem-index elem-newvalue ls)
    (setq i -1)
    (mapcar
      (lambda (item)
        (cl-incf i)
        (cond
          ((= i elem-index) elem-newvalue)
          (t item)))
      ls))