org-agenda 设置每月最后一天为 deadline

发布: 2022-01-08   更新: 2022-01-09   标签: tips org-mode text

在 org-agenda 中,支持设置重复的任务,示例如下:

1
2
** TODO Pay the rent
   DEADLINE: <2005-10-01 Sat +1m>

日期最后的 +1m 表示每个月重复一次,其他的时间单位还有 y 年、w 周、d 天、h 时。 在将 TODO 任务转为 DONE 时,org 会自动开启新一轮的 deadline,比如上面任务完成一次后会变成:

1
2
3
4
5
6
** TODO Pay the rent
   DEADLINE: <2005-11-01 Tue +1m>
:PROPERTIES:
:LAST_REPEAT: [2022-01-08 Sat 23:33]
:END:
- CLOSING NOTE [2022-01-08 Sat 23:33]

但是这里有一个问题,即 org 月首时间循环是没问题的,但是不能正确支持按月末时间循环。如果上面示例中的日期变成 2005-01-31 ,执行一次 DONE 后,日期则变成了 2005-03-03 ,而不是 2005-02-28 。网上有类似提问:Schedule org task for last day of every month?,回答里介绍了两种方法:

  1. 增加 diary-last-day-of-month 函数,
  2. org-clone-subtree-with-time-shift 来把十二个月的代办全部生成出来

第一种方法我测试了下没有成功,于是转向第二种,第二种方法看上去挺笨的,但是其实更灵活,可以灵活调整每个月的时间。但是直接用 org-clone-subtree-with-time-shift 来生成不是很灵活,DEADLINE 倒是可以动态生成,但是标题都是一样的。比如:

1
2
* TODO My Task
SCHEDULED: <2022-01-30 Sun>

用 1m 作为间隔,拷贝 4 份,效果如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
* TODO My Task
SCHEDULED: <2022-01-30 Sun>
* TODO My Task
SCHEDULED: <2022-03-02 Wed>
* TODO My Task
SCHEDULED: <2022-03-30 Wed>
* TODO My Task
SCHEDULED: <2022-04-30 Sat>
* TODO My Task
SCHEDULED: <2022-05-30 Mon>

如果生成标题时能传入变量就好了。这里突然想到之前用的 abo-abo/tiny 这个插件,它可以非常方便的生成有规律的序列。对于我这里的需求,可以输入以下模板:

1
m1\n12 |* TODO %d  \n<2022-%02d-30>

然后光标移动到行末,然后 M-x tiny-expand ,就会得到如下的文本:

1
2
3
4
5
6
7
8
9
* TODO 1 
<2022-01-30>
* TODO 2 
<2022-02-30>
* TODO 3 
<2022-03-30>
* TODO 4 
<2022-04-30>
... 省略后面的

然后选中所有的 2022(可以用 multiple-cursorsmc/mark-all-like-this ),然后执行 C-c C-c ,这样日期就会修正,效果如下:

1
2
3
4
5
6
7
8
* TODO 1 
<2022-01-30 Sun>
* TODO 2 
<2022-03-02 Wed>
* TODO 3 
<2022-03-30 Wed>
* TODO 4 
<2022-04-30 Sat>

最后再手动调整下 2 月份的日期即可,其他有 31 天的月可以忽略,毕竟差一天也能接受。如果对 tiny-expand、multiple-cursors 等插件比较熟悉,不到一分钟就可以完整上面的配置。

这就是用基于纯文本的 org 来管理代办的好处,可以用自己熟悉的命令来实现自己的个性化需求。

https://img.alicdn.com/imgextra/i4/581166664/O1CN01zpRJsk1z6A7F8j03o_!!581166664.png
EmacsTalk 2022 年代办


收听方式

反馈