Is there a way to have any TODO (whether entered by org-capture or manually) to get a CREATED timestamp added like SCHEDULED and DEADLINE ?

i.e. today I have entries like:

* TODO call mom  
  SCHEDULED: <2017-09-26 Tue>
* TODO walk the dog
* TODO buy milk

and over time the list grows and I often find myself wanting to clear out old entries or review if still relevant - but without any info on when entries was added that is hard. I would love if I could tell org-mode to add CREATED: so the above would be:

* TODO call mom  
  SCHEDULED: <2017-09-26 Tue> CREATED: [2015-09-26]
* TODO walk the dog
  CREATED: [2017-09-21]
* TODO buy milk
  CREATED: [2017-01-26]

Any ideas/suggestions?

I'm thinking an on-save action or similar would be best but not sure how to about it.

I typically insert TODO headings using M-S-return (bound to org-insert-todo-heading). You might find this suitable for your purposes:

(defun my/log-todo-creation-date (&rest ignore)
  "Log TODO creation time in the property drawer under the key 'CREATED'."
  (when (and (org-get-todo-state)
             (not (org-entry-get nil "CREATED")))
    (org-entry-put nil "CREATED" (format-time-string (cdr org-time-stamp-formats)))))

(advice-add 'org-insert-todo-heading :after #'my/log-todo-creation-date)
(advice-add 'org-insert-todo-heading-respect-content :after #'my/log-todo-creation-date)
(advice-add 'org-insert-todo-subheading :after #'my/log-todo-creation-date)

If you want to add creation dates to TODO's that you typed manually you could catch those proactively by (temporarily) advising org-get-todo-state itself (so that org internals effectively create the property entries for you). Alternately, the org-after-todo-state-change-hook hook may be sufficient. This would log creation dates for existing TODO's the next time you cycle/set the todo state (such as with org-shiftright):

(add-hook 'org-after-todo-state-change-hook #'my/log-todo-creation-date)

These create a property entry like the following:

** TODO Test
:PROPERTIES:
:CREATED:  <2017-09-26 Tue 23:33>
:END:
  • yeah I got that somewhat working - I really would just prefer the CREATED part would be listed same way as CLOSED, SCHEDULED, DEADLINE is so it doesn't add 3 more lines. – Max Rydahl Andersen Sep 27 '17 at 9:53
  • I use (org-entry-put nil "CREATED" (format-time-string "[%Y-%m-%d %a]")) to insert an inactive time stamp in the same format as Org, otherwise these items show up in agenda view. – mmorin Oct 29 at 11:20

I use the org-expiry package to do this. Here's what I've got in my init file:

  (req-package org-expiry
    :loader :el-get-local
    :require org-capture
    :init (progn
            (org-expiry-insinuate)
            (setq
             org-expiry-created-property-name "CREATED" ; Name of property when an item is created
             org-expiry-inactive-timestamps   t         ; Don't have everything in the agenda view
             )))

Notice that I'm using req-package. You could create a similar effect with just this:

(require 'org-expiry)
(org-expiry-insinuate)
(setq org-expiry-created-property-name "CREATED")
  • I added those but I see nothing being added when I type in "* TODO test" how is it triggered ? – Max Rydahl Andersen Sep 26 '17 at 7:54
  • it seem to only add something when I change the type (i.e. from TODO to DONE) and then it add it as a properties section meaning it gets very verbose - but I guess I can live with that for now. Just need to grok how to get it actually added to all things I create. – Max Rydahl Andersen Sep 26 '17 at 9:38
  • Out of curiosity, why do you have :require org-capture in there? – kshenoy Jun 28 at 16:57
  • @kshenoy, you're right, it's unnecessary. Currently, I'm using this code: (req-package org-expiry :el-get t :config (org-expiry-insinuate) (customize-set-variable 'org-expiry-inactive-timestamps t)) ; don't have everything in the agenda view – jeffkowalski Jun 29 at 20:36
  • @jeffkowalski Thanks for the explanation. I wasn't sure if I was unaware of some dependency between the two. – kshenoy Jul 3 at 21:13

Cross-posted from a similar question on StackOverflow.

Here is a lightweight solution that does not require an external package, adapted from the answer by @ebpa but without the extra lines for the properties drawer. It works with org-capture and with M-S-RET. Put this in your Emacs initialization file (e.g. ~/.emacs):

(defun insert-created-date(&rest ignore)
  (insert (format-time-string
       (concat "\nCREATED: "
           (cdr org-time-stamp-formats))
       ))
  (org-back-to-heading) ; in org-capture, this folds the entry; when inserting a heading, this moves point back to the heading line
  (move-end-of-line()) ; when inserting a heading, this moves point to the end of the line
  )


                    ; add to the org-capture hook
(add-hook 'org-capture-before-finalize-hook 
         #'insert-created-date
)

                    ; hook it to adding headings with M-S-RET
                    ; do not add this to org-insert-heading-hook, otherwise this also works in non-TODO items
                    ; and Org-mode has no org-insert-todo-heading-hook
(advice-add 'org-insert-todo-heading :after #'insert-created-date)

I did not add this function to state changes (e.g., from plain heading to TODO) because then @ebpa's answer is cleaner.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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