New patches.  See attached.

Tests pass after each patch on emacs 30.2.
Tests pass after final patch on emacs 28 and 29.
Tests pass after final patch with TZ set to UTC, Europe/Istanbul, and
America/New_York.


Ihor Radchenko <[email protected]> writes:

>
> Do note that there is no guarantee that an agenda item is pointing to
> Org mode buffer. It can point to diary.
>
I see.  I have added a check and a new test for that scenario.

>> As we transition to using the org-element API in more places, we are 
>> eventually
>> going to have to figure out what to do about the agenda.  My WIP patch shows
>> one way to get access to the org element API but I assume it comes with some
>> serious performance issues (still have no clue how parsing/caching works so
>> please let me know if my assumption is correct).
>
> Repetitive calls to org-element-at-point are cached. See
> `org-element--cache-hash-left' and the variables nearby.
>
I'm still not sure what the performance impacts are but you make it
sound like it probably isn't much.

>From be6e3749954f3b6b6da7ca6c3b796dc5f8a11ca8 Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Tue, 10 Feb 2026 16:37:40 -0500
Subject: [PATCH 1/3] lisp/ox-latex.el (org-latex-make-preamble): Make Emacs 28
 compatible

The third argument to 'mapconcat' is not optional on Emacs 28.
---
 lisp/ox-latex.el | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el
index 82828730b..d134b164f 100644
--- a/lisp/ox-latex.el
+++ b/lisp/ox-latex.el
@@ -2033,7 +2033,8 @@ org-latex-make-preamble
 		                 (if (not class-options) header
 		                   (replace-regexp-in-string
 			            "^[ \t]*\\\\documentclass\\(\\(\\[[^]]*\\]\\)?\\)"
-			            class-options header t nil 1))))))
+			            class-options header t nil 1)))
+                                nil)))
 	      (user-error "Unknown LaTeX class `%s'" class))))
     (org-latex-guess-polyglossia-language
      (org-latex-guess-babel-language

base-commit: 008b16fc1cfd0f1efdb6314e19d5c8212c2bf3c0
-- 
2.52.0

>From 4c3e299a3f516f53a2ff74fe717d98ec26a0f5f2 Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Sun, 16 Nov 2025 18:00:08 -0500
Subject: [PATCH 2/3] Fix agenda sorting based on multiple types of timestamps

Previously, attempting to sort on multiple types of timestamps
(eg. SCHEDULED and DEADLINE) would result in only sorting on one of
them.

* lisp/org-agenda.el (org-cmp-ts): Try harder to get a timestamp
(org-agenda-entry-get-agenda-timestamp): Add comment explaining the
functions shortcomings.
* testing/lisp/test-org-agenda.el (test-org-agenda/sorting/time): Test
now passes.

Reported-by: Jonas Olofsson <[email protected]>
Link: https://list.orgmode.org/[email protected]
---
 lisp/org-agenda.el              | 20 ++++++++++++++++++++
 testing/lisp/test-org-agenda.el |  1 -
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/lisp/org-agenda.el b/lisp/org-agenda.el
index 106a0919b..bf22a17dc 100644
--- a/lisp/org-agenda.el
+++ b/lisp/org-agenda.el
@@ -5599,6 +5599,9 @@ org-agenda-entry-get-agenda-timestamp
 Given an element, point, or marker EPOM, returns a cons cell of the
 timestamp and the timestamp type relevant for the sorting strategy in
 `org-agenda-sorting-strategy-selected'."
+  ;; FIXME: The logic here is flawed as all of the timestamps can be
+  ;; important for sorting since multiple sorting functions are called
+  ;; in sequence.  See `org-cmp-ts' which works around this issue.
   (let (ts ts-date-type)
     (save-match-data
       (cond ((org-em 'scheduled-up 'scheduled-down
@@ -7598,6 +7601,23 @@ org-cmp-ts
   (cl-flet ((get-timestamp (entry)
               (or (and (string-match type (or (get-text-property 1 'type entry) ""))
                        (get-text-property 1 'ts-date entry))
+                  (when-let* ((epom (get-text-property 1 'org-hd-marker entry))
+                              ;; Abort if we are in a diary buffer
+                              (epom (org-with-base-buffer (marker-buffer epom)
+                                      (and (derived-mode-p 'org-mode)
+                                           (org-element-at-point epom))))
+                              (timestamp
+                               (cond
+                                ((string-equal type "")
+                                 (or (org-entry-get epom "SCHEDULED")
+                                     (org-entry-get epom "DEADLINE")
+                                     (org-entry-get epom "TIMESTAMP")
+                                     (org-entry-get epom "TIMESTAMP_IA")))
+                                ((string-equal type "scheduled") (org-entry-get epom "SCHEDULED"))
+                                ((string-equal type "deadline") (org-entry-get epom "DEADLINE"))
+                                ((string-equal type "timestamp_ia") (org-entry-get epom "TIMESTAMP_IA"))
+                                ((string-equal type "timestamp") (org-entry-get epom "TIMESTAMP")))))
+                    (org-time-string-to-absolute timestamp))
                   (if org-agenda-sort-notime-is-late most-positive-fixnum -1))))
     (let ((ta (get-timestamp a))
           (tb (get-timestamp b)))
diff --git a/testing/lisp/test-org-agenda.el b/testing/lisp/test-org-agenda.el
index 312104ab1..7c5dd89df 100644
--- a/testing/lisp/test-org-agenda.el
+++ b/testing/lisp/test-org-agenda.el
@@ -767,7 +767,6 @@ test-org-agenda/sorting
 
 (ert-deftest test-org-agenda/sorting/time ()
   "Test if `org-agenda' sorts according to `org-agenda-sorting-strategy'."
-  :expected-result :failed
   ;; FIXME: test the following
   ;; timestamp-up
   ;; tsia-up
-- 
2.52.0

>From a5c0ada1670eedebcbc8ca7cb056ae2a410e4ba1 Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Wed, 28 Jan 2026 11:44:12 -0500
Subject: [PATCH 3/3] Testing: New test 'test-org-agenda/sorting/time/diary

* testing/lisp/test-org-agenda.el:
(test-org-agenda/sorting/time/diary): New test
---
 testing/lisp/test-org-agenda.el | 108 ++++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)

diff --git a/testing/lisp/test-org-agenda.el b/testing/lisp/test-org-agenda.el
index 7c5dd89df..df275afc1 100644
--- a/testing/lisp/test-org-agenda.el
+++ b/testing/lisp/test-org-agenda.el
@@ -831,6 +831,114 @@ test-org-agenda/sorting/time
 scheduled yesterday
 both yesterday"))))))
 
+(ert-deftest test-org-agenda/sorting/time/diary ()
+  "Test if `org-agenda' sorts according to `org-agenda-sorting-strategy'.
+Test both diary timestamps and inclusion from a diary file."
+  (cl-flet ((call-agenda-with-priority (priority)
+              (let ((diary-file (expand-file-name "examples/diary-file" org-test-dir))
+                    (diary-date-forms '((month "[-/]" day "[^-/0-9]")
+                                        (year "[-/]" month "[-/]" day "[^0-9]")
+                                        (monthname " *" day "[^-0-9]")
+                                        (year " *" monthname " *" day "[^0-9]")
+                                        (dayname "\\W")))
+                    (org-agenda-custom-commands
+                     `(("f" "no fluff" agenda ""
+                        ((org-agenda-include-diary t)
+                         (org-agenda-start-day "-1d")
+                         (org-agenda-span 3)
+                         (org-agenda-overriding-header "")
+                         (org-agenda-use-time-grid nil)
+                         (org-agenda-format-date "")
+                         (org-agenda-show-all-dates nil)
+                         (org-agenda-todo-keyword-format "")
+                         (org-agenda-prefix-format "")
+                         (org-agenda-sorting-strategy ',priority))))))
+                (org-agenda nil "f")
+                (string-trim
+                 (substring-no-properties
+                  (buffer-string))))))
+    (org-test-at-time "2019-01-08"
+      (org-test-agenda-with-agenda
+          "* scheduled yesterday
+SCHEDULED: <%%(org-date 2019 01 07)>
+* scheduled today
+SCHEDULED: <%%(org-date 2019 01 08)>
+* scheduled tomorrow
+SCHEDULED: <%%(org-date 2019 01 09)>
+* deadline yesterday
+DEADLINE: <%%(org-date 2019 01 07)>
+* deadline today
+DEADLINE: <%%(org-date 2019 01 08)>
+* deadline tomorrow
+DEADLINE: <%%(org-date 2019 01 09)>
+* both yesterday
+SCHEDULED: <%%(org-date 2019 01 07)> DEADLINE: <%%(org-date 2019 01 07)>
+* both today
+SCHEDULED: <%%(org-date 2019 01 08)> DEADLINE: <%%(org-date 2019 01 08)>
+* both tomorrow
+SCHEDULED: <%%(org-date 2019 01 09)> DEADLINE: <%%(org-date 2019 01 09)>
+* diary time in headline 08:00-09:00
+<%%(org-date 2019 01 08)>
+* diary time in timestamp
+<%%(org-date 2019 01 08) 09:00-10:00>
+* diary time in both 10:00-01:00
+<%%(org-date 2019 01 08) 10:00-01:00>
+* diary yesterday
+<%%(org-date 2019 01 07)>
+* diary today
+<%%(org-date 2019 01 08)>
+* diary tomorrow
+<%%(org-date 2019 01 09)>
+* nothing"
+        (should
+         (string-equal
+          (call-agenda-with-priority '(deadline-up scheduled-up ts-up time-up))
+          "deadline yesterday
+both yesterday
+scheduled yesterday
+both yesterday
+diary yesterday
+
+deadline today
+both today
+scheduled today
+both today
+diary time in headline 08:00-09:00
+diary time in timestamp
+diary time in both 10:00-01:00
+diary today
+test code: f0bcf0cd8bad93c1451bb6e1b2aaedef5cce7cbb
+
+deadline tomorrow
+both tomorrow
+scheduled tomorrow
+both tomorrow
+diary tomorrow"))
+        (should
+         (string-equal
+          (call-agenda-with-priority '(scheduled-down deadline-down ts-down time-down))
+          "diary yesterday
+deadline yesterday
+both yesterday
+scheduled yesterday
+both yesterday
+
+test code: f0bcf0cd8bad93c1451bb6e1b2aaedef5cce7cbb
+diary today
+diary time in both 10:00-01:00
+diary time in timestamp
+diary time in headline 08:00-09:00
+deadline today
+both today
+scheduled today
+both today
+
+diary tomorrow
+deadline tomorrow
+both tomorrow
+scheduled tomorrow
+both tomorrow"))))))
+
 (ert-deftest test-org-agenda/tags-sorting ()
   "Test if `org-agenda' sorts tags according to `org-tags-sort-function'."
   (let ((string-length< (lambda (s1 s2)
-- 
2.52.0

Reply via email to