Hello,

I apologize for the delay in re-submitting this.  I have created a
number of tests to test the current implementation.  Then I have
reimplemented `org-clock-sum' using the org-element api (ensuring all
tests still pass).  Then I added a new feature that will issue a warning
if the timestamp is not fully specified.

This brings a big performance improvement.

Thanks,

Morgan

>From 96e2c6dfbd597000ee90b91efe74d34cb7234c03 Mon Sep 17 00:00:00 2001
From: Morgan Smith <morgan.j.sm...@outlook.com>
Date: Wed, 17 Apr 2024 17:51:35 -0400
Subject: [PATCH 1/6] Testing: Test clock times without timestamps

* testing/lisp/test-org-clock.el (test-org-clock/clocktable/insert):
Add a clock time that does not include timestamps.
---
 testing/lisp/test-org-clock.el | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/testing/lisp/test-org-clock.el b/testing/lisp/test-org-clock.el
index 8a196ee96..62e4d7507 100644
--- a/testing/lisp/test-org-clock.el
+++ b/testing/lisp/test-org-clock.el
@@ -345,13 +345,12 @@ test-org-clock/clocktable/insert
    (equal
     "| Headline     | Time   |
 |--------------+--------|
-| *Total time* | *1:00* |
+| *Total time* | *2:00* |
 |--------------+--------|
-| H1           | 1:00   |"
+| H1           | 2:00   |"
     (org-test-with-temp-text "* H1\n<point>"
-      (insert (org-test-clock-create-clock ". 1:00" ". 2:00"))
-
-      (goto-line 2)
+      (insert (org-test-clock-create-clock ". 1:00" ". 2:00")
+              "CLOCK: => 1:00\n")
       (require 'org-clock)
       (org-dynamic-block-insert-dblock "clocktable")
 
-- 
2.50.1

>From bee73f771bb7c3d3525583379404d734c53517a9 Mon Sep 17 00:00:00 2001
From: Morgan Smith <morgan.j.sm...@outlook.com>
Date: Wed, 8 May 2024 10:36:07 -0400
Subject: [PATCH 2/6] Testing: New test test-org-clock/clocktable/open-clock

* testing/lisp/test-org-clock.el
(test-org-clock/clocktable/open-clock): New test.
---
 testing/lisp/test-org-clock.el | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/testing/lisp/test-org-clock.el b/testing/lisp/test-org-clock.el
index 62e4d7507..1ae91ebba 100644
--- a/testing/lisp/test-org-clock.el
+++ b/testing/lisp/test-org-clock.el
@@ -362,6 +362,39 @@ test-org-clock/clocktable/insert
 	     (point) (progn (search-forward "#+END:") (line-end-position 0))))
 	(delete-region (point) (search-forward "#+END:\n")))))))
 
+(ert-deftest test-org-clock/clocktable/open-clock ()
+  "Test open clocks.
+Open clocks should be ignored unless it is clocked in and
+`org-clock-report-include-clocking-task' is t."
+  (let ((time-reported "| Headline     | Time   |
+|--------------+--------|
+| *Total time* | *1:00* |
+|--------------+--------|
+| H1           | 1:00   |")
+        (time-not-reported "| Headline     | Time   |
+|--------------+--------|
+| *Total time* | *0:00* |"))
+    (dolist (org-clock-report-include-clocking-task '(nil t))
+      (dolist (actually-clock-in '(nil t))
+        ;; Without leading characters then `org-clock-hd-marker' doesn't
+        ;; get updated when clocktable is inserted and test fails.
+        (org-test-with-temp-text "\n*<point> H1\n"
+          (should
+           (equal
+            (if (and org-clock-report-include-clocking-task
+                     actually-clock-in)
+                time-reported
+              time-not-reported)
+            (progn
+              (if actually-clock-in
+                  (org-clock-in nil (- (float-time) (* 60 60)))
+                (goto-char (point-max))
+                (insert (org-test-clock-create-clock "-1h")))
+              ;; Unless tstart and tend are fully specified it doesn't work
+              (test-org-clock-clocktable-contents ":tstart \"<-2d>\" :tend \"<tomorrow>\""))))
+          (when actually-clock-in
+            (org-clock-cancel)))))))
+
 (ert-deftest test-org-clock/clocktable/ranges ()
   "Test ranges in Clock table."
   ;; Relative time: Previous two days.
-- 
2.50.1

>From 36b6f4925f0cb2a647eabca8f1950f511d32841d Mon Sep 17 00:00:00 2001
From: Morgan Smith <morgan.j.sm...@outlook.com>
Date: Sat, 9 Aug 2025 14:04:07 -0400
Subject: [PATCH 3/6] Testing: Add tests for clocktables from inline tasks

* testing/lisp/test-org-clock.el
(test-org-clock/clocktable/inlinetask/insert)
(test-org-clock/clocktable/inlinetask/open-clock): New tests
---
 testing/lisp/test-org-clock.el | 75 ++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/testing/lisp/test-org-clock.el b/testing/lisp/test-org-clock.el
index 1ae91ebba..0058b9dc7 100644
--- a/testing/lisp/test-org-clock.el
+++ b/testing/lisp/test-org-clock.el
@@ -1497,5 +1497,80 @@ test-org-clock/special-range
                    cases))))
     (should-not failed)))
 
+;;; Inline tasks clocktable
+
+(require 'org-inlinetask)
+
+(ert-deftest test-org-clock/clocktable/inlinetask/insert ()
+  "Test insert clocktable on an inline task."
+  :expected-result :failed
+  ;; Instead of the expected result we get this monstrosity:
+  ;; | *Total time* | *2:00* |
+  ;; |--------------+--------|
+  ;; | H1           |   2:00 |
+  ;; | I            |   2:00 |
+  (should
+   (equal
+    "| Headline     | Time   |
+|--------------+--------|
+| *Total time* | *2:00* |
+|--------------+--------|
+| H1           | 2:00   |"
+    (let ((org-inlinetask-min-level 5)
+          (org-adapt-indentation t))
+      (org-test-with-temp-text "* H1
+***** I
+<point>
+***** END
+foo"
+      (insert (org-test-clock-create-clock ". 1:00" ". 2:00")
+              "CLOCK: => 1:00\n")
+      (require 'org-clock)
+      (goto-char (point-min))
+      (org-dynamic-block-insert-dblock "clocktable")
+      (unwind-protect
+          (save-excursion
+            (when (search-forward "#+CAPTION:") (forward-line))
+            (buffer-substring-no-properties
+             (point) (progn (search-forward "#+END:") (line-end-position 0))))
+        (delete-region (point) (search-forward "#+END:\n"))))))))
+
+(ert-deftest test-org-clock/clocktable/inlinetask/open-clock ()
+  "Test open clocks on an inline task.
+Open clocks should be ignored unless it is clocked in and
+`org-clock-report-include-clocking-task' is t."
+  :expected-result :failed
+  ;; Makes sense that this would fail if the previous test fails
+  (let ((time-reported "| Headline     | Time   |
+|--------------+--------|
+| *Total time* | *1:00* |
+|--------------+--------|
+| H1           | 1:00   |")
+        (time-not-reported "| Headline     | Time   |
+|--------------+--------|
+| *Total time* | *0:00* |"))
+    (dolist (org-clock-report-include-clocking-task '(nil t))
+      (dolist (actually-clock-in '(nil t))
+        (org-test-with-temp-text
+         "* H1
+***** I
+<point>
+***** END
+foo"
+         (should
+          (equal
+           (if (and org-clock-report-include-clocking-task
+                    actually-clock-in)
+               time-reported
+             time-not-reported)
+           (progn
+             (if actually-clock-in
+                 (org-clock-in nil (- (float-time) (* 60 60)))
+               (insert (org-test-clock-create-clock "-1h")))
+             (test-org-clock-clocktable-contents ""))))
+         (when actually-clock-in
+           (org-clock-cancel)))))))
+
 (provide 'test-org-clock)
+
 ;;; test-org-clock.el end here
-- 
2.50.1

>From d3d0174bb3bc9be108d50cca0e738db4d9f2598b Mon Sep 17 00:00:00 2001
From: Morgan Smith <morgan.j.sm...@outlook.com>
Date: Sat, 9 Aug 2025 14:09:20 -0400
Subject: [PATCH 4/6] Testing: test for malformed clock lines

* testing/lisp/test-org-clock.el
(test-org-clock/clocktable/malformed-clock-lines): New test
---
 testing/lisp/test-org-clock.el | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/testing/lisp/test-org-clock.el b/testing/lisp/test-org-clock.el
index 0058b9dc7..df587a789 100644
--- a/testing/lisp/test-org-clock.el
+++ b/testing/lisp/test-org-clock.el
@@ -1316,6 +1316,36 @@ test-org-clock/clocktable/hidefiles
           (test-org-clock-clocktable-contents
            (format ":hidefiles t :scope (lambda () (list %S))" the-file))))))))
 
+(ert-deftest test-org-clock/clocktable/malformed-clock-lines ()
+  "Test clocktable with malformed clock lines."
+  (let (org-warning)
+    (cl-letf* (((symbol-function #'org-display-warning)
+                (lambda (message) (setq org-warning message))))
+      (should
+   (equal
+    ;; Obviously this is a very wrong output but it remains
+    ;; consistent with how parsing has been done historically.
+    "| Headline     | Time   |
+|--------------+--------|
+| *Total time* | *0:05* |
+|--------------+--------|
+| H1           | 0:05   |"
+    (org-test-with-temp-text "* H1\n<point>"
+      (insert
+       "CLOCK: [2012-01-01 sun. 00rr:04]--[2012-01-01 sun. 00:05] =>  0:01")
+      (require 'org-clock)
+      (org-dynamic-block-insert-dblock "clocktable")
+      (goto-char (point-min))
+      (unwind-protect
+          (save-excursion
+            (when (search-forward "#+CAPTION:") (forward-line))
+            (buffer-substring-no-properties
+             (point) (progn (search-forward "#+END:") (line-end-position 0))))
+        (delete-region (point) (search-forward "#+END:\n"))))))
+      ;; TODO: No warnings are issued!
+      ;; (should org-warning)
+      )))
+
 ;;; Mode line
 
 (ert-deftest test-org-clock/mode-line ()
-- 
2.50.1

>From a7dd20d452adcc111588aeb12f28abd402594ffe Mon Sep 17 00:00:00 2001
From: Morgan Smith <morgan.j.sm...@outlook.com>
Date: Thu, 11 Apr 2024 12:23:21 -0400
Subject: [PATCH 5/6] lisp/org-clock.el (org-clock-sum): Rewrite using element
 api

* lisp/org-clock.el (org-clock-sum): Rewrite using element api.
(org--clock-ranges): New function.
* testing/lisp/test-org-clock.el
(test-org-clock/clocktable/open-clock): Don't specify tstart and tend
because I don't need to anymore.  It does still work with them
specified.
(test-org-clock/clocktable/inlinetask/insert): Enable test.
(test-org-clock/clocktable/inlinetask/open-clock): Enable test.
---
 lisp/org-clock.el              | 205 +++++++++++++++++----------------
 testing/lisp/test-org-clock.el |  11 +-
 2 files changed, 105 insertions(+), 111 deletions(-)

diff --git a/lisp/org-clock.el b/lisp/org-clock.el
index 8b1752384..28a929e61 100644
--- a/lisp/org-clock.el
+++ b/lisp/org-clock.el
@@ -33,15 +33,13 @@
 
 (require 'cl-lib)
 (require 'org)
+(require 'org-element)
 
 (declare-function calendar-iso-to-absolute "cal-iso" (date))
 (declare-function notifications-notify "notifications" (&rest params))
 (declare-function org-element-property "org-element-ast" (property node))
-(declare-function org-element-contents-end "org-element" (node))
-(declare-function org-element-end "org-element" (node))
 (declare-function org-element-type "org-element-ast" (node &optional anonymous))
 (declare-function org-element-type-p "org-element-ast" (node types))
-(defvar org-element-use-cache)
 (declare-function org-inlinetask-at-task-p "org-inlinetask" ())
 (declare-function org-inlinetask-goto-beginning "org-inlinetask" ())
 (declare-function org-inlinetask-goto-end "org-inlinetask" ())
@@ -2069,105 +2067,68 @@ org-clock-sum
 HEADLINE-FILTER is a zero-arg function that, if specified, is called for
 each headline in the time range with point at the headline.  Headlines for
 which HEADLINE-FILTER returns nil are excluded from the clock summation.
-PROPNAME lets you set a custom text property instead of :org-clock-minutes."
+PROPNAME lets you set a custom text property instead of :org-clock-minutes.
+
+Clocking entries that are open (as in don't have an end time) that are
+not the current clocking entry will be ignored."
   (with-silent-modifications
-    (let* ((re (concat "^\\(\\*+\\)[ \t]\\|^[ \t]*"
-		       org-clock-string
-		       "[ \t]*\\(?:\\(\\[.*?\\]\\)-+\\(\\[.*?\\]\\)\\|=>[ \t]+\\([0-9]+\\):\\([0-9]+\\)\\)"))
-	   (lmax 30)
-	   (ltimes (make-vector lmax 0))
-	   (level 0)
-	   (tstart (cond ((stringp tstart) (org-time-string-to-seconds tstart))
-			 ((consp tstart) (float-time tstart))
-			 (t tstart)))
-	   (tend (cond ((stringp tend) (org-time-string-to-seconds tend))
-		       ((consp tend) (float-time tend))
-		       (t tend)))
-	   (t1 0)
-	   time)
-      (remove-text-properties (point-min) (point-max)
-			      `(,(or propname :org-clock-minutes) t
-				:org-clock-force-headline-inclusion t))
-      (save-excursion
-	(goto-char (point-max))
-	(while (re-search-backward re nil t)
-          (let* ((element (save-match-data (org-element-at-point)))
-                 (element-type (org-element-type element)))
-	    (cond
-	     ((and (eq element-type 'clock) (match-end 2))
-	      ;; Two time stamps.
-              (condition-case nil
-	          (let* ((timestamp (org-element-property :value element))
-		         (ts (float-time
-                              (org-encode-time
-                               (list 0
-                                     (org-element-property :minute-start timestamp)
-                                     (org-element-property :hour-start timestamp)
-                                     (org-element-property :day-start timestamp)
-                                     (org-element-property :month-start timestamp)
-                                     (org-element-property :year-start timestamp)
-                                     nil -1 nil))))
-		         (te (float-time
-                              (org-encode-time
-                               (list 0
-                                     (org-element-property :minute-end timestamp)
-                                     (org-element-property :hour-end timestamp)
-                                     (org-element-property :day-end timestamp)
-                                     (org-element-property :month-end timestamp)
-                                     (org-element-property :year-end timestamp)
-                                     nil -1 nil))))
-		         (dt (- (if tend (min te tend) te)
-			        (if tstart (max ts tstart) ts))))
-	            (when (> dt 0) (cl-incf t1 (floor dt 60))))
-                (error
-                 (org-display-warning (format "org-clock-sum: Ignoring invalid %s" (org-current-line-string))))))
-	     ((match-end 4)
-	      ;; A naked time.
-	      (setq t1 (+ t1 (string-to-number (match-string 5))
-			  (* 60 (string-to-number (match-string 4))))))
-	     ((memq element-type '(headline inlinetask)) ;A headline
-	      ;; Add the currently clocking item time to the total.
-	      (when (and org-clock-report-include-clocking-task
-		         (eq (org-clocking-buffer) (current-buffer))
-		         (eq (marker-position org-clock-hd-marker) (point))
-		         tstart
-		         tend
-		         (>= (float-time org-clock-start-time) tstart)
-		         (<= (float-time org-clock-start-time) tend))
-	        (let ((time (floor (org-time-convert-to-integer
-				    (time-since org-clock-start-time))
-				   60)))
-		  (setq t1 (+ t1 time))))
-	      (let* ((headline-forced
-		      (get-text-property (point)
-				         :org-clock-force-headline-inclusion))
-		     (headline-included
-		      (or (null headline-filter)
-			  (save-excursion
-			    (save-match-data (funcall headline-filter))))))
-	        (setq level (- (match-end 1) (match-beginning 1)))
-	        (when (>= level lmax)
-		  (setq ltimes (vconcat ltimes (make-vector lmax 0)) lmax (* 2 lmax)))
-	        (when (or (> t1 0) (> (aref ltimes level) 0))
-		  (when (or headline-included headline-forced)
-		    (if headline-included
-		        (cl-loop for l from 0 to level do
-			         (aset ltimes l (+ (aref ltimes l) t1))))
-		    (setq time (aref ltimes level))
-		    (goto-char (match-beginning 0))
-                    (put-text-property (point) (line-end-position)
-				       (or propname :org-clock-minutes) time)
-		    (when headline-filter
-		      (save-excursion
-		        (save-match-data
-			  (while (org-up-heading-safe)
-			    (put-text-property
-			     (point) (line-end-position)
-			     :org-clock-force-headline-inclusion t))))))
-		  (setq t1 0)
-		  (cl-loop for l from level to (1- lmax) do
-			   (aset ltimes l 0))))))))
-	(setq org-clock-file-total-minutes (aref ltimes 0))))))
+    (let ((tstart (cond ((stringp tstart) (org-time-string-to-seconds tstart))
+                        ((consp tstart) (float-time tstart))
+                        (t tstart)))
+          (tend (cond ((stringp tend) (org-time-string-to-seconds tend))
+                      ((consp tend) (float-time tend))
+                      (t tend)))
+          (propname (or propname :org-clock-minutes))
+          (t1 0)
+          (total 0)
+          time)
+      (remove-text-properties (point-min) (point-max) `(,propname t))
+      (org-element-cache-map
+       (lambda (headline-or-inlinetask)
+         (when (or (null headline-filter)
+                   (save-excursion
+                     (funcall headline-filter)))
+           (mapc
+            (lambda (range)
+              (setq time
+                    (pcase range
+                      (`(,_ . open)
+                       (when (and org-clock-report-include-clocking-task
+                                  (eq (org-clocking-buffer) (current-buffer))
+                                  (eq (marker-position org-clock-hd-marker)
+                                      (org-element-begin headline-or-inlinetask))
+                                  (or (not tstart)
+                                      (>= (float-time org-clock-start-time) tstart))
+                                  (or (not tend)
+                                      (<= (float-time org-clock-start-time) tend)))
+                         (floor (org-time-convert-to-integer
+                                 (time-since org-clock-start-time))
+                                60)))
+                      ((pred floatp) range)
+                      (`(,time1 . ,time2)
+                       (let* ((ts (float-time time1))
+                              (te (float-time time2))
+                              (dt (- (if tend (min te tend) te)
+                                     (if tstart (max ts tstart) ts))))
+                         (floor dt 60)))))
+              (when (and time (> time 0)) (cl-incf t1 time)))
+            (org--clock-ranges headline-or-inlinetask))
+           (when (> t1 0)
+             (setq total (+ total t1))
+             (org-element-lineage-map headline-or-inlinetask
+                 (lambda (parent)
+                   (put-text-property
+                    (org-element-begin parent) (1- (org-element-contents-begin parent))
+                    propname
+                    (+ t1 (or (get-text-property
+                               (org-element-begin parent)
+                               propname)
+                              0))))
+               ;; TODO: can inlinetasks contain inlinetasks?
+               '(headline) t))
+           (setq t1 0)))
+       :narrow t)
+      (setq org-clock-file-total-minutes total))))
 
 (defun org-clock-sum-current-item (&optional tstart)
   "Return time, clocked on current item in total."
@@ -2182,6 +2143,48 @@ org-clock-sum-current-item
       (org-clock-sum tstart)
       org-clock-file-total-minutes)))
 
+(defun org--clock-ranges (headline)
+  "Return a list of clock ranges of HEADLINE.
+Does not recurse into subheadings.
+Ranges are in one of these formats:
+   (cons time . time)
+   (cons time . \\='open) The clock does not have an end time
+   float               The number of minutes as a float"
+  (unless (org-element-type-p headline '(headline inlinetask))
+    (error "Argument must be a headline"))
+  (and
+   (org-element-contents-begin headline) ;; empty headline
+   (or
+    (org-element-cache-get-key headline :clock-ranges)
+    (let ((clock-ranges
+           (org-element-cache-map
+            (lambda (elem)
+              (when (org-element-type-p elem 'clock)
+                (if-let* ((timestamp (org-element-property :value elem)))
+                    (condition-case nil
+                        (cons (org-timestamp-to-time timestamp)
+                              (if (eq 'running (org-element-property :status elem))
+                                  'open
+                                (org-timestamp-to-time timestamp t)))
+                      (error
+                       (org-display-warning (format "org-clock-sum: Ignoring invalid timestamp: %s"
+                                                    (org-element-property :raw-value timestamp)))))
+                  (when (org-element-property :duration elem)
+                    (org-duration-to-minutes (org-element-property :duration elem))))))
+            ;; XXX: using these arguments would be more intuitive
+            ;; but don't seem to work due to bugs in
+            ;; `org-element-cache-map'
+            ;; :restrict-elements '(clock)
+            ;; :after-element headline
+            :granularity 'element
+            :next-re org-element-clock-line-re
+            :from-pos (org-element-contents-begin headline)
+            :to-pos (save-excursion
+                      (goto-char (org-element-begin headline))
+                      (org-entry-end-position)))))
+      (org-element-cache-store-key headline :clock-ranges clock-ranges)
+      clock-ranges))))
+
 ;;;###autoload
 (defun org-clock-display (&optional arg)
   "Show subtree times in the entire buffer.
diff --git a/testing/lisp/test-org-clock.el b/testing/lisp/test-org-clock.el
index df587a789..8d715de48 100644
--- a/testing/lisp/test-org-clock.el
+++ b/testing/lisp/test-org-clock.el
@@ -390,8 +390,7 @@ test-org-clock/clocktable/open-clock
                   (org-clock-in nil (- (float-time) (* 60 60)))
                 (goto-char (point-max))
                 (insert (org-test-clock-create-clock "-1h")))
-              ;; Unless tstart and tend are fully specified it doesn't work
-              (test-org-clock-clocktable-contents ":tstart \"<-2d>\" :tend \"<tomorrow>\""))))
+              (test-org-clock-clocktable-contents ""))))
           (when actually-clock-in
             (org-clock-cancel)))))))
 
@@ -1533,12 +1532,6 @@ test-org-clock/special-range
 
 (ert-deftest test-org-clock/clocktable/inlinetask/insert ()
   "Test insert clocktable on an inline task."
-  :expected-result :failed
-  ;; Instead of the expected result we get this monstrosity:
-  ;; | *Total time* | *2:00* |
-  ;; |--------------+--------|
-  ;; | H1           |   2:00 |
-  ;; | I            |   2:00 |
   (should
    (equal
     "| Headline     | Time   |
@@ -1569,8 +1562,6 @@ test-org-clock/clocktable/inlinetask/open-clock
   "Test open clocks on an inline task.
 Open clocks should be ignored unless it is clocked in and
 `org-clock-report-include-clocking-task' is t."
-  :expected-result :failed
-  ;; Makes sense that this would fail if the previous test fails
   (let ((time-reported "| Headline     | Time   |
 |--------------+--------|
 | *Total time* | *1:00* |
-- 
2.50.1

>From 334bcee379ebc7fbbad1f3315ac971bf65250670 Mon Sep 17 00:00:00 2001
From: Morgan Smith <morgan.j.sm...@outlook.com>
Date: Sat, 9 Aug 2025 16:36:59 -0400
Subject: [PATCH 6/6] lisp/org-clock.el: Check that clocklines are fully
 specified

* lisp/org-clock.el (org--clock-ranges): Check that clocklines are
fully specified.  Issue a warning if they are not.
* testing/lisp/test-org-clock.el
(test-org-clock/clocktable/malformed-clock-lines): Check that warnings
are issued.
---
 lisp/org-clock.el              | 36 ++++++++++++++++++++++++++--------
 testing/lisp/test-org-clock.el |  6 ++----
 2 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/lisp/org-clock.el b/lisp/org-clock.el
index 28a929e61..d70eec3ac 100644
--- a/lisp/org-clock.el
+++ b/lisp/org-clock.el
@@ -2161,14 +2161,34 @@ org--clock-ranges
             (lambda (elem)
               (when (org-element-type-p elem 'clock)
                 (if-let* ((timestamp (org-element-property :value elem)))
-                    (condition-case nil
-                        (cons (org-timestamp-to-time timestamp)
-                              (if (eq 'running (org-element-property :status elem))
-                                  'open
-                                (org-timestamp-to-time timestamp t)))
-                      (error
-                       (org-display-warning (format "org-clock-sum: Ignoring invalid timestamp: %s"
-                                                    (org-element-property :raw-value timestamp)))))
+                    (progn
+                      (unless
+                          (and
+                           (org-element-property :minute-start timestamp)
+                           (org-element-property :hour-start timestamp)
+                           (org-element-property :day-start timestamp)
+                           (org-element-property :month-start timestamp)
+                           (org-element-property :year-start timestamp)
+                           ;; When the end doesn't exist, it is set to the start.
+                           ;; This means we can't check that the end is fully specified.
+                           ;; (org-element-property :minute-end timestamp)
+                           ;; (org-element-property :hour-end timestamp)
+                           ;; (org-element-property :day-end timestamp)
+                           ;; (org-element-property :month-end timestamp)
+                           ;; (org-element-property :year-end timestamp)
+                           )
+                        (org-display-warning
+                         (format "org-clock-sum: Timestamp not fully specified: %s\n    Assuming value is %s"
+                                 (org-element-property :raw-value timestamp)
+                                 (org-element-timestamp-interpreter timestamp nil))))
+                      (condition-case nil
+                          (cons (org-timestamp-to-time timestamp)
+                                (if (eq 'running (org-element-property :status elem))
+                                    'open
+                                  (org-timestamp-to-time timestamp t)))
+                        (error
+                         (org-display-warning (format "org-clock-sum: Ignoring invalid timestamp: %s"
+                                                      (org-element-property :raw-value timestamp))))))
                   (when (org-element-property :duration elem)
                     (org-duration-to-minutes (org-element-property :duration elem))))))
             ;; XXX: using these arguments would be more intuitive
diff --git a/testing/lisp/test-org-clock.el b/testing/lisp/test-org-clock.el
index 8d715de48..0a6aabcc5 100644
--- a/testing/lisp/test-org-clock.el
+++ b/testing/lisp/test-org-clock.el
@@ -1340,10 +1340,8 @@ test-org-clock/clocktable/malformed-clock-lines
             (when (search-forward "#+CAPTION:") (forward-line))
             (buffer-substring-no-properties
              (point) (progn (search-forward "#+END:") (line-end-position 0))))
-        (delete-region (point) (search-forward "#+END:\n"))))))
-      ;; TODO: No warnings are issued!
-      ;; (should org-warning)
-      )))
+        (delete-region (point) (search-forward "#+END:\n")))))))
+      (should (string-prefix-p "org-clock-sum: Timestamp not fully specified: " org-warning))))
 
 ;;; Mode line
 
-- 
2.50.1

Reply via email to