7

I have so many tasks I do far away from my computer with emacs. Now, when I change state of a TODO, it just logs the current time into the drawer. But the difference with actual time of the event may be many hours, if not days.

Is there a way to make it prompt for a timestamp I'd like it to log?

6

I've wanted the exact same "I did this yesterday" behavior for a while and never got around to trying to implement it. But now if I can get points for it ....

This behavior seems to be hard-coded into org-todo. The line in org.el that sets the CLOSED timestamp is (org-add-planning-info 'closed (org-current-effective-time)) and the LOGBOOK notes are added by org-add-log-setup, which in turn calls org-effective-current-time. org-effective-current-time does what it sounds like and returns the effective time.

The obvious solution is to temporarily change org-effective-current-time to something that prompts for a date. But then we get prompted for the date multiple times with every call, which is annoying. I don't know a good way to avoid it, but you can just save off the user inputed value and keep that around until the end of the function.

This code seems to work and only prompts once when a state change would be logged.

(defun org-todo-with-date (&optional arg)
  (interactive "P")
  (cl-letf* ((org-read-date-prefer-future nil)
             (my-current-time (org-read-date t t nil "when:" nil nil nil))
            ((symbol-function #'org-current-effective-time)
             #'(lambda () my-current-time)))
    (org-todo arg)
    )) 
| improve this answer | |
  • Great, thanks. I refactored your code a bit. Please feel free to paste this to your answer: gist.github.com/koddo/aa6d497e0d1df4023915 – koddo Feb 21 '15 at 15:43
  • 1
    Seems that the next occurrence of a repeated task (e.g. .+7d) wouldn't be scheduled correctly with this function (it is scheduled as if the task were finished today). – xji Apr 19 '19 at 22:51
  • @xji I've been annoyed by that behavior too, but don't have a solution. These kinds of hacks are all pretty fragile. – erikstokes Apr 20 '19 at 16:10
  • @erikstokes Yeah now I'm thinking of giving up org-mode as the tool to manage recurring tasks/habits. Some mobile apps do it better. I'll try to just use it to produce a list of one-time tasks with priority attached, review them every day and put timestamps on them to schedule my daily agenda. – xji Apr 22 '19 at 9:30
2

You can layer more hacks on top the first answer to address the problem with scheduling repeaters not updating correctly as so. Note that if LAST_REPEAT is set, it will be set to the actual date, not the chosen one. I wish Org would add this as a first-class feature; the actual date leaks into org-todo in many places; I'm sure this answer still misses some:

    (defun org-todo-with-date (&optional arg)
      (interactive "P")
      (cl-letf* ((org-read-date-prefer-future nil)
                 (my-current-time (org-read-date t t nil "when:" nil nil nil))
                 ((symbol-function #'current-time)
                  #'(lambda () my-current-time))
                 ((symbol-function #'org-today)
                  #'(lambda () (time-to-days my-current-time)))
                 ((symbol-function #'org-current-effective-time)
                  #'(lambda () my-current-time)))
        (org-todo arg)))
| improve this answer | |
1

And here is another layer to fix LAST_REPEAT case:

(defun org-todo-with-date (&optional arg)
  (interactive "P")
  (cl-letf* ((org-read-date-prefer-future nil)
             (my-current-time (org-read-date t t nil "when:" nil nil nil))
             ((symbol-function 'current-time)
              #'(lambda () my-current-time))
             ((symbol-function 'org-today)
              #'(lambda () (time-to-days my-current-time)))
             ((symbol-function 'org-current-effective-time)
              #'(lambda () my-current-time))
             (super (symbol-function 'format-time-string))
             ((symbol-function 'format-time-string)
              #'(lambda (fmt &optional time time-zone)
                  (funcall super fmt my-current-time time-zone))))
    (org-todo arg)))

hopefully format-time-string is only called from org-auto-repeat-maybe in org-todo context and only for LAST_REPEAT insertion.

Anyway you can always copy the org-todo defun to your emacs.el init file and modify it there instead of cherry-pickifying functions with cl-letf (althought it's kind of cool to do it)

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.