12

How do I schedule a repeating org-mode task for the last day of every month?

As is, when I schedule a task like DEADLINE: <2017-03-31 Fri +1m>, marking it done shifts the next date to DEADLINE: <2017-05-01 Fri +1m> which would be a day too late if the deadline is the end of the month. Dates scheduled for the beginning of the month properly advance to the first of the following month, regardless of number of days in the month, so this problem only occurs at the end of the month.

I would prefer to do this using pure org-mode and avoid diary dates if possible since some commands and views can't handle diary dates. That said, a diary solution is better than nothing!

This question is distinct from Schedule repeating Org event for day of month since scheduling for the end of the month is a common edge case which requires special handling to account for the variable number of days in each month.

holocronweaver
  • 1,319
  • 10
  • 22
  • 1
    Possible duplicate of [Schedule repeating Org event for day of month](http://emacs.stackexchange.com/questions/21220/schedule-repeating-org-event-for-day-of-month) See also the link in the linked-answer for additional solutions. – lawlist Mar 24 '17 at 21:40
  • None of those are solutions to my problem. Please see edit. – holocronweaver Mar 25 '17 at 23:03
  • I've posted an answer for both the diary and/or the agenda buffer. The methodology in the link to the potential *duplicate* [?] thread is the same in that this question calls for a `sexp` and the linked question states that a `sexp` can be used to achieve the desired result. – lawlist Mar 26 '17 at 01:56
  • I see that you edited your question to add the word *repeating*, and I thought perhaps you did not see the second example for `* My Task ...` at the bottom of the answer. In what way does my answer not address your needs? – lawlist Mar 27 '17 at 20:04
  • 1
    @lawlist The edit was based on a slightly improved version of the question I sent to the org-mode mailing list. I will accept your answer in a day or two if no one provides a native solution; I am already using yours in my own config. =) – holocronweaver Mar 27 '17 at 20:09
  • 1
    This is very much a hack, but try setting your deadline on the 30th: it will stay on the 30th (until next February - that's why it's a hack :-)) Then if you meet the deadline and the month has 31 days, take the next day off! – NickD Mar 27 '17 at 22:08

2 Answers2

12

The custom function diary-list-day-of-month (set forth below) can be used to create a repeating org-mode task or to create a diary entry that will appear on the *Calendar* and/or in the *Org Agenda* buffer (if org-agenda-include-diary is t).

;;; ORG-MODE:  * My Task
;;;              SCHEDULED: <%%(diary-last-day-of-month date)>
;;; DIARY:  %%(diary-last-day-of-month date) Last Day of the Month
;;; See also:  (setq org-agenda-include-diary t)
;;; (diary-last-day-of-month '(2 28 2017))
(defun diary-last-day-of-month (date)
"Return `t` if DATE is the last day of the month."
  (let* ((day (calendar-extract-day date))
         (month (calendar-extract-month date))
         (year (calendar-extract-year date))
         (last-day-of-month
            (calendar-last-day-of-month month year)))
    (= day last-day-of-month)))

Here is a sexp for the diary file, which can appear in the *Calendar* and/or in the *Org Agenda* buffer -- see org-agenda-include-diary:

%%(diary-last-day-of-month date) Last Day of the Month

Here is an example org-mode entry that can appear in the *Org Agenda* -- e.g., M-x org-agenda RET followed by the letter a:

* My Task
  SCHEDULED: <%%(diary-last-day-of-month date)>
lawlist
  • 18,826
  • 5
  • 37
  • 118
  • It is a shame a custom function is needed, but at least it works and is easy to read! Do you know if org is able to create advanced warnings for dates of this form? My understanding from the docs is it cannot. – holocronweaver Mar 26 '17 at 06:22
  • I read about the same limitation earlier today, but have not yet had an occasion to experiment with the advance warning feature in conjunction with an `org-mode` timestamp containing a `sexp`. If you believe a last day of the month feature would be helpful and want to see it built-in someday, the `org-mode` team has a mailing list where they accept feature requests and bug reports. – lawlist Mar 26 '17 at 07:24
  • 2
    I was reading this on account of wanting something a bit different, which turned out to exist already: Scheduling the first/last Wednesday of every month" with `SCHEDULED: <%%(diary-float t 3 1)>` or `SCHEDULED: <%%(diary-float t 3 -1)>` respectively. – phils Mar 25 '19 at 01:55
3

Wow I never realized such a basic feature didn't exist. Unfortunate...

At first I thought you would be able to set up a warning, so that you would have the deadline for the 1st of every month and then warn you the day prior but that didn't work either.

As far as I can tell your best option would be to use a subtask for each month of the year. Each of those subtasks would have a 1y repeat. This isn't actually so bad being you can just collapse it anyways!

You can use M-x org-clone-subtree-with-time-shift to generate duplicated tasks and then update each deadline make sure the dates are correct.

If you were not going to use TODO's and mark them complete you could use multiple DEADLINES for one task but I think multiple tasks is a better solution.

You should be able to just copy/paste this and change the titles.

* TODO Monthly Task
** TODO Monthly Task
   DEADLINE: <2017-01-31 Tue +1y>

** TODO Monthly Task
   DEADLINE: <2017-02-28 Tue +1y>

** TODO Monthly Task
   DEADLINE: <2017-03-31 Fri +1y>

** TODO Monthly Task
   DEADLINE: <2017-04-30 Sun +1y>

** TODO Monthly Task
   DEADLINE: <2017-05-31 Wed +1y>

** TODO Monthly Task
   DEADLINE: <2017-06-30 Fri +1y>

** TODO Monthly Task
   DEADLINE: <2017-07-31 Mon +1y>

** TODO Monthly Task
   DEADLINE: <2017-08-31 Thu +1y>

** TODO Monthly Task
   DEADLINE: <2017-09-30 Sat +1y>

** TODO Monthly Task
   DEADLINE: <2017-10-31 Tue +1y>

** TODO Monthly Task
   DEADLINE: <2017-11-30 Thu +1y>

** TODO Monthly Task
   DEADLINE: <2017-12-31 Sun +1y>

It isn't the most elegant solution, but it does work.

Travis
  • 41
  • 3
  • 5
    February has 29 days sometimes... –  Mar 25 '17 at 12:50
  • Yep, this is exactly what I have been doing without an automated solution. Alas, I have so many tasks due at the end of the month that it is becoming burdensome. – holocronweaver Mar 25 '17 at 22:58