diff --git a/lisp/org-element.el b/lisp/org-element.el index 203f45a33..baa605548 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -4152,6 +4152,8 @@ (defun org-element-timestamp-interpreter (timestamp _) (let ((day-start (org-element-property :day-start timestamp)) (month-start (org-element-property :month-start timestamp)) (year-start (org-element-property :year-start timestamp))) + ;; Return nil when start date is not available. Could also + ;; throw an error, but the current behavior is historical. (when (and day-start month-start year-start) (let* ((repeat-string (concat @@ -4184,39 +4186,82 @@ (defun org-element-timestamp-interpreter (timestamp _) (and (org-string-nw-p warning-string) (concat " " warning-string)) (cdr brackets)))) (concat + ;; Opening backet: [ or < (car brackets) + ;; Starting date/time: YYYY-MM-DD DAY[ HH:MM] (format-time-string - (org-time-stamp-format (when (and minute-start hour-start) t) 'no-brackets) + ;; `org-time-stamp-formats'. + (org-time-stamp-format + ;; Ignore time unless both HH:MM are available. + ;; Ignore means (car org-timestamp-formats). + (and minute-start hour-start) + 'no-brackets) (org-encode-time 0 (or minute-start 0) (or hour-start 0) day-start month-start year-start)) - (let((hour-end (org-element-property :hour-end timestamp)) - (minute-end (org-element-property :minute-end timestamp))) + ;; Range: -HH:MM or TIMESTAMP-END--[YYYY-MM-DD DAY HH:MM] + (let ((hour-end (org-element-property :hour-end timestamp)) + (minute-end (org-element-property :minute-end timestamp))) (pcase type ((or `active `inactive) + ;; `org-element-timestamp-parser' use this type + ;; when no time/date range is provided. So, + ;; should normally return nil in this clause. (pcase range-type (`nil + ;; `org-element-timestamp-parser' will never assign end times here. + ;; End time will always imply `active-range' or `inactive-range' TYPE. + ;; But manually built timestamps may contain + ;; anything, so check for end times anyway. (when (and hour-start hour-end minute-start minute-end (or (/= hour-start hour-end) (/= minute-start minute-end))) + ;; Could also throw an error. Return range + ;; timestamp nevertheless to preserve + ;; historical behavior. (format "-%02d:%02d" hour-end minute-end))) ((or `timerange `daterange) (error "`:range-type' must be `nil' for `active'/`inactive' type")))) + ;; Range must be present. ((or `active-range `inactive-range) (pcase range-type + ;; End time: -HH:MM. + ;; Fall back to start time if end time is not defined (arbitrary historical choice). + ;; Error will be thrown if both end and begin time is not defined. (`timerange (format "-%02d:%02d" (or hour-end hour-start) (or minute-end minute-start))) - ((or `nil `daterange) + ;; End date: TIMESTAMP-END--[YYYY-MM-DD DAY HH:MM + ((or `daterange + ;; Should never happen in the output of `org-element-timestamp-parser'. + ;; Treat as an equivalent of `daterange' arbitrarily. + `nil) (concat + ;; repeater + warning + closing > or ] + ;; This info is duplicated in date ranges. timestamp-end "--" (car brackets) (format-time-string - (org-time-stamp-format (when (and minute-end hour-end) t) 'no-brackets) + ;; `org-time-stamp-formats'. + (org-time-stamp-format + ;; Ignore time unless both HH:MM are available. + ;; Ignore means (car org-timestamp-formats). + (and minute-end hour-end) + 'no-brackets) (org-encode-time + ;; Closing HH:MM missing is a valid scenario. 0 (or minute-end 0) (or hour-end 0) + ;; YEAR/MONTH/DAY-END will always be present + ;; for `daterange' range-type, as parsed by + ;; `org-element-timestamp-parser'. + ;; For manually constructed timestamp + ;; object, arbitrarily fall back to starting + ;; date. (or (org-element-property :day-end timestamp) day-start) (or (org-element-property :month-end timestamp) month-start) (or (org-element-property :year-end timestamp) year-start))))))))) + ;; repeater + warning + closing > or ] + ;; This info is duplicated in date ranges. timestamp-end)))) + ;; diary type. (org-element-property :raw-value timestamp)))) ;;;; Underline