Rewrite timestamps in Org-export

Rewrite timestamps in Org-export

August 29, 2023

While making figuring out how much running I’ve done this summer, I realized that I wanted to gussy up the way that published timestamps look. The way it looks in Emacs is more like this:

| Date             | Distance (km) |     Time | Minutes | Pace (min/km) |
|------------------+---------------+----------+---------+---------------|
| [2023-07-22 Sat] |         12.93 | 01:30:31 |   90.52 |           7.0 |
| [2023-06-17 Sat] |         13.40 | 01:11:58 |   71.97 |           5.4 |
| [2023-06-10 Sat] |         17.52 | 01:58:23 |  118.38 |           6.8 |
#+TBLFM: $4='(org-duration-to-minutes $3);%.2f::$5='(/ $4 $2);%.1fN

I want to keep those in the actual file, but maybe make them look nicer for humans when I export it. I use ox-hugo and Org-mode’s built-in publish so I can use a convenient feature, org-export-filter-timestamp-functions. It’s a list of functions to run specifically on timestamps on export, so that seems remarkably convenient.

(with-eval-after-load 'ox
  (require 'ox-icalendar)
  (add-to-list 'org-export-filter-timestamp-functions
               #'env-filter-timestamp))

I started by adding a custom function to org-export-filter-timestamp-functions which I’ll set up now.

(defun env-filter-timestamp (string _backend _comm)
  "Remove [<>] around time-stamps from STRING.
I actually don't know what _COMM is. BACKEND is the type of
conversion we're doing, in this case either some form of
HTML/Markdown or LaTeX. The filter receives the entire output
timestamp as STRING and then processes it before saving."
  (if (string-match-p ":" string)
      (format-time-string "%A, %B %-e, %Y at %H:%M"
                          (org-time-string-to-time string))
    (format-time-string "%A, %B %-e, %Y"
                        (org-time-string-to-time string))))

The function which I’m calling env-filter-timestamp takes three things, a string which is timestamp from the Org file, the output backend such as Markdown, HTML or Hugo, and something called a communication channel plist. No idea what that is.

I’m not sure if there’s a better way to figure out if the timestamp has an actual time in it. I tried the function org-timestamp-has-time-p but it didn’t work the way I wanted, so I just look to see if there’s a colon that must be present as the HH:MM separator. Emacs time conversion does not make sense to me, so I use Org’s system. That’s not an issue here as I can rely on it existing. It’s pretty easy to make work; format-time-string requires time in the form of (TICKS . HZ) which is what the function org-times-string-to-time provides. So it’s easy to format the time any way I want here. And look at how nice it came out (this is a copy-paste from above):

Date Distance (km) Time Minutes Pace (min/km)
Saturday, July 22, 2023 12.93 01:30:31 90.52 7.0
Saturday, June 17, 2023 13.40 01:11:58 71.97 5.4
Saturday, June 10, 2023 17.52 01:58:23 118.38 6.8

See? That’s great!