Sorting todos by org-roam file creation date prefix

I have no idea how useful this would be to others, but in case it is, I thought I would share it. And I’m also interested in hearing how others would have accomplished the same result with a better method.

My org-roam files have a “YYMMDD_” prefix. When I used to run org-todo-list, the todos were showing up in a pretty random order as far as I could tell. I decided I wanted to have them in descending order of the date prefix of the file they appear in. When I googled for this, I found one person’s approach (under my/org-agenda-sort-longterm-tags). I modified that slightly to arrive at:

;;  this function sorts todos by the yymmdd timestamp in the roam filename
;;  so the todos in the most recently created files are at the top.
(defun <=> (a b)
  "Compare A and B, returning 1, 0, or -1"
  (cond ((= a b) 0)
        ((> a b) 1)
        ((< a b) -1)))

(defun gpc/org-agenda-cmp-user-defined (a b)
  "Compare two org-agenda-events by their org-roam file prefix datestamp"
  (let* ((regex "\\(2[0-9][0-9][0-9][0-9][0-9]\\)")
         (date-a (if (string-match regex a)
                     (string-to-number (or (match-string 1 a) "0"))
         (date-b (if (string-match regex b)
                     (string-to-number (or (match-string 1 b) "0"))
    (<=> date-a date-b)))

(setq org-agenda-cmp-user-defined 'gpc/org-agenda-cmp-user-defined)

What do people think of this a) desired outcome b) approach for achieving it? I personally assume the code above could be more elegant, but I’m not sure how I would do that.

I feel that if the approach works for you and you like it, it’s a good one :slight_smile:

Without understanding what output values are really required for sorting todos, if I were to do something like that, I would try to use org-time* built-in macros like this.

For the timestamp prefix you have, you would need to covert it to a standard ISO-like format (my/convert-date).

Then it would be a matter of using some combinations of org-time* macros (in the let part). This does not return -1, 0, 1 like your approach does, so it may not work for your purpose.

  (defun my/convert-date (prefix)
     (substring prefix 0 2)
     (substring prefix 2 4)
     (substring prefix 4 6)))
  ;; Do something like this in a comparison function
  (let ((date1 "210605")
        (date2 "210606"))
    (org-time<= (my/convert-date date1)
                (my/convert-date date2)))  

If you want to sort some sequence (like a list), then I’d see if I could use seq-sort-by, etc. like: (seq-sort-by #'my/convert-date #'org-time<= list) – this is probably not what you can use for your purpose…

1 Like