Leo Ufimtsev
Leo Ufimtsev

Reputation: 6512

Emacs org-mode, repeat tasks M-F but not weekends?

I have tasks that I do every day (e.g bugzilla triage), but I only do those Monday to friday. Not on the weekends.

When I use something like this:

SCHEDULED: <2015-02-07 Sat ++1d>

It repeats it every day, including weekends. Can I change this?

Upvotes: 40

Views: 12254

Answers (6)

cashpw
cashpw

Reputation: 11

I've written a package to handle this: repeat-todo. It supports weekdays, weekends, and custom combinations of days:

* TODO Water the flowers
SCHEDULED: <... ++1d>
:PROPERTIES:
:REPEAT: weekdays
:END
* TODO Go for a walk
SCHEDULED: <... ++1d>
:PROPERTIES:
:REPEAT: weekend
:END:
* TODO Get the mail
SCHEDULED: <... ++1d>
:PROPERTIES:
:REPEAT: M W F
:END:

The key methods are:

(defun repeat-todo--parse-property (prop-value)
  "Return repeating days for PROP-VALUE as list of day numbers (sun=0, mon=1, etc)."
  (let ((case-fold-search nil))
    (cond
     ((string-match "weekday\\(s\\)?" prop-value)
      '(1 2 3 4 5))
     ((string-match "weekend\\(s\\)?" prop-value)
      '(6 0))
     (t
      (let ((repeat-days '())
            (prop-values (string-split " " prop-value 'omit-nulls)))
        (dolist (value prop-values)
          ;; su, sun, sunday
          ((when (string-match "^su\\(n\\(day\\)?\\)?")
             (push 0 repeat-days)))
          ;; m, mon, monday
          ((string-match "^m\\(on\\(day\\)?\\)?") (push 1 repeat-days))
          ;; t, tue, tues, tuesday
          ((when (string-match "^t\\(ue\\(s\\(day\\)?\\)?")
             (push 2 repeat-days)))
          ;; w, wed, wednesday
          ((when (string-match "^w\\(ed\\(nesday\\)?\\)?")
             (push 3 repeat-days)))
          ;; r, thu, thur, thurs, thursday
          ((when (or (string= "r")
                     (string= "R")
                     (string-match "thu\\(r\\(s\\(day\\)?\\)?\\)?"))
             (push 4 repeat-days)))
          ;; f, fri, friday
          ((when (string-match "^f\\(ri\\(day\\)?\\)?")
             (push 5 repeat-days)))
          ;; sa, sat, saturday
          ((when (string-match "^sa\\(t\\(urday\\)?\\)?")
             (push 6 repeat-days))))
        (reverse repeat-days))))))

(defun repeat-todo--next-scheduled-time (current-scheduled-time weekdays)
  "Return the next valid, by WEEKDAYS, time after CURRENT-SCHEDULED-TIME.

WEEKDAYS: See `repeat-todo--weekdays'."
  (when weekdays
    (let ((new-scheduled-time
           (time-add current-scheduled-time (days-to-time 1))))
      (while (not
              (member
               (string-to-number
                (format-time-string "%u" new-scheduled-time))
               weekdays))
        (setq new-scheduled-time
              (time-add new-scheduled-time (days-to-time 1))))
      new-scheduled-time)))

(defun repeat-todo--reschedule (point-or-marker)
  "Reschedule heading at POINT-OR-MARKER to the next appropriate weekday."
  (when (and repeat-todo-mode
             (org-entry-is-done-p)
             (repeat-todo--p point-or-marker))
    (org-schedule
     nil
     (string-replace
      " 00:00" ""
      (format-time-string
       "%F %H:%M"
       ;; Schedule to the day before the next schedule time because
       ;; it'll get moved forward one day past when we schedule it
       (time-subtract
        (repeat-todo--next-scheduled-time
         (org-get-scheduled-time point-or-marker)
         (repeat-todo--parse-property
          (or (org-entry-get point-or-marker repeat-todo--property) "")))
        (days-to-time 1)))))))

Upvotes: 1

Jason Tian
Jason Tian

Reputation: 23

I had the same requirement and was able to resolve it by writing my own code. You can find it here:

https://gist.github.com/jsntn/542443e8505d62cac635eacd8bce458a

Note: ensure that the TODO task has the workday tag set, like this:

* Task          :workday:
SCHEDULED: <2024-08-02 Fri .+1d>

Upvotes: 0

loopernow
loopernow

Reputation: 11

There is the Habit Plus package, at https://github.com/myshevchuk/org-habit-plus, which augments the Habits functionality in Org Mode.

See Org Mode Habits in the manual: https://orgmode.org/manual/Tracking-your-habits.html

From the Readme.org at the Habits Plus github page:

Installation

As simple as putting the org-habit-plus.el into the load path and adding org-habit-plus to the org-modules list.

How it works

As simple as specifying the weekdays (1 = Monday, 7 = Sunday, space separated), on which a habit is expected to be performed, in the :HABIT_WEEKDAYS: property.

So, first you would enable the Habits module in Org and set your task as a habit, specifying how often it repeats. See the Org manual link above for details.

Then you would install Habits Plus. See the github page for the org-habit-plus.el file.

Then you would add a :HABIT_WEEKDAYS: property to your habit and give that property a value of 1 2 3 4 5 to indicate it should be completed Monday through Friday.

Upvotes: 1

ironfish
ironfish

Reputation: 331

One way is to simply have a TODO for each week day, eg:

* TODO My task  
  SCHEDULED: <2015-02-09 Mon ++1w>

* TODO My task  
  SCHEDULED: <2015-02-10 Tue ++1w>

This is different than another answer:

* TODO My task
  SCHEDULED: <2015-02-09 Mon ++1w>
  SCHEDULED: <2015-02-10 Tue ++1w>
  SCHEDULED: <2015-02-11 Wed ++1w>
  SCHEDULED: <2015-02-12 Thu ++1w>
  SCHEDULED: <2015-02-13 Fri ++1w>

Which has an issue, as pointed out by someone:

There is an issue with this. When I close a task, it moves all the scheduled items forward by a week, not just the one that is due :-/

This issue occurs because all timestamps are associated with one TODO.

Upvotes: 14

Chris McMahan
Chris McMahan

Reputation: 2690

If you just need a reminder, and don't need to mark them as 'DONE' in your org-file, you could use the calendar integration for these situations.

** Triage Bugzilla Entries 09:00-10:00
   <%%(memq (calendar-day-of-week date) '(1 2 3 4 5))>

This will insert an entry into your daily agenda for weekdays only, but not a task.

Upvotes: 34

tanzoniteblack
tanzoniteblack

Reputation: 671

Unfortunately, org-mode doesn't seem to support this in a simple command, but you can replicate this by setting up multiple weekly repeats for the same item like so:

* TODO My task
  SCHEDULED: <2015-02-09 Mon ++1w>
  SCHEDULED: <2015-02-10 Tue ++1w>
  SCHEDULED: <2015-02-11 Wed ++1w>
  SCHEDULED: <2015-02-12 Thu ++1w>
  SCHEDULED: <2015-02-13 Fri ++1w>

Upvotes: 11

Related Questions