在org-mode中为TODO添加创建日期属性

36

我读了org-mode手册,但找不到简单的方法在新创建的TODO中添加CREATED字段。与 org-log-done 结合使用,可以计算关闭特定TODO所需的时间。在使用归档文件时,这尤其有用。

示例:

* TODO Do something
  CREATED:  [2012-09-02 Sun 23:02]
* DONE Do something else
  CREATED: [2012-09-02 Sun 20:02]
  CLOSED: [2012-09-02 Sun 22:02]

我希望在保存文件时,能够自动添加CREATED字段到新任务(即那些还没有该字段的任务)中。

有什么建议可以实现这个功能吗?使用像Git这样的工具来跟踪TODO创建并不适合我。


2
你打算使用Capture模板添加任务吗?还是手动插入它们?如果你使用Capture模板,你可以通过模板包含它。在保存时添加会稍微麻烦一些。 - Jonathan Leech-Pepin
1
我通常手动插入任务,实际上我并不打算改变这一点,因为我想保持编辑文本文件的感觉。 - Renke Grunwald
8个回答

19
我使用org-expiry实现该功能,它位于org的contrib目录中。
我使用的基本配置是:
;; Allow automatically handing of created/expired meta data.
(require 'org-expiry)
;; Configure it a bit to my liking
(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
)

(defun mrb/insert-created-timestamp()
  "Insert a CREATED property using org-expiry.el for TODO entries"
  (org-expiry-insert-created)
  (org-back-to-heading)
  (org-end-of-line)
  (insert " ")
)

;; Whenever a TODO entry is created, I want a timestamp
;; Advice org-insert-todo-heading to insert a created timestamp using org-expiry
(defadvice org-insert-todo-heading (after mrb/created-timestamp-advice activate)
  "Insert a CREATED property using org-expiry.el for TODO entries"
  (mrb/insert-created-timestamp)
)
;; Make it active
(ad-activate 'org-insert-todo-heading)

如果您正在使用捕获功能,它不会自动工作,需要一些粘合剂。我在这里发布了完整的配置: https://gist.github.com/4037694

5
谢谢。我认为这是一个不错的解决方案。然而,我只是将这段代码放在我的初始化文件里:(require 'org-expiry) (org-expiry-insinuate) (setq org-expiry-inactive-timestamps t)。我没有做其他修改。 - Renke Grunwald
此外,好处在于每当您更改待办事项的标签时,它会添加CREATED属性;由于我无论如何都会对每个待办事项执行此操作,因此我从未遇到缺少CREATED属性的情况。非常好。 - Renke Grunwald
我将你的代码添加到我的配置文件中,但似乎对org-todos没有任何影响。 - azureai

9
一种更轻量级的解决方案是在TODO状态中添加!标志:
(setq org-todo-keywords '((sequence "TODO(!)" "DONE")))

然后:

* TODO get of your ass
  - State "TODO"    from    [2016-06-03 to. 10:35]

虽然它不太美观。

参考:http://orgmode.org/org.html#Tracking-TODO-state-changes


9

您不需要使用“defadvice”修改函数来运行捕获过期代码。您应该使用钩子:

(add-hook 'org-capture-before-finalize-hook 
          (lambda()
               (save-excursion
                    (org-back-to-heading)
                    (org-expiry-insert-created))))

同样适用于“org-insert-todo-heading”。有一个钩子:

(add-hook 'org-insert-todo-heading-hook 
          (lambda()
               (save-excursion
                    (org-back-to-heading)
                    (org-expiry-insert-created))))

1
这是一个很好的答案,但在钩子中放置lambda表达式是一个坏主意,特别是当您重复使用它两次时 :) - Clément
调用(org-back-to-heading)是必要的吗? - Moyamo
@Moyamo似乎不是,(save-excursion)也不是。org-expiry-insert-created自己就能完成两件事情,因此可以直接使用它来进行钩子操作,不需要使用lambda函数。 - JoL
很棒的答案。这也适用于普通标题的创建,而不仅仅是TODO标题。 - xji
1
我需要做什么才能让它工作?我使用doom emacs并将代码包含在我的config.el中,然后执行了doom sync,但没有任何反应。org-todos仍然表现得一样,没有添加创建时间戳。 - azureai

6

这里有一个被埋藏的宝藏:

(setq org-treat-insert-todo-heading-as-state-change t)

我在这里找到了它的来源,是作为回应某人想要一个org-insert-todo-heading-hook的。我刚试用了一下,当你使用org-insert-todo-heading时,它会计入状态变更,所以例如:#+TODO: TODO(t!) | ...将添加一个日志。

@JohnDeBord 请查看跟踪状态更改 - NickD

6

Org提供了一个钩子org-after-todo-state-change-hook,您可以在此处使用:

org-after-todo-state-change-hook是在‘org.el’中定义的变量。

文档:

当TODO项目的状态更改后运行的钩子。 新状态(带有TODO关键字或nil的字符串)可在Lisp变量‘org-state’中使用。

使用方法如下:

(require 'org-expiry)

(add-hook 'org-after-todo-state-change-hook
          (lambda ()
            (when (string= org-state "TODO")
              (save-excursion
                (org-back-to-heading)
                (org-expiry-insert-created)))))

org-expiry是org-contrib的一部分,它包含在org ELPA的org-plus-contrib软件包中


1
这个不适用于 M-S-RET (org-insert-todo-heading)。 - Clément

4
如果您使用org-capture创建所有待办事项,则以下捕获模板可以解决问题:
(setq org-capture-templates
'(
    ("t" "TODO Task" entry (file+headline "~/inbox.org" "Tasks")
         "* TODO %?\nCREATED: %u\nSRC: %a\n%i\n")
    ))

结果将会大致如下所示:
* Tasks
** TODO Dummy task
CREATED: [2015-05-08 Fri]
SRC: [[file:~/path/to/file/where/you/created/the/task.org::*heading"][heading]]

2
这里提供了一种轻量级的解决方案,不需要外部包。我从@MarcinAntczak的回答、@Clément的评论以及这个类似的帖子中得到了它。它可以与org-captureM-S-RET一起使用。将以下内容放入您的Emacs初始化文件中(例如~/.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)

我没有将此功能添加到状态更改中(例如,从普通标题到 TODO ),因为它需要在属性抽屉中,并且我不喜欢有那些额外的行。如果您喜欢在属性中使用它,请使用在此线程中定义的函数。

1

您可以在创建时添加时间戳,而无需进行任何配置,但它不会被标记为“CREATED”。与其手动输入TODO,不如使用C-c C-t。然后它将被记录为“状态从"""更改为TODO,并带有时间戳。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接