Search code examples
emacselispformat-string

How can I add a format specifier to `format-time-string`?


I have the following function definition:

(defun nth (n)
  (format
   (concat
    "%d"
    (if (memq n '(11 12 13)) "th"
      (let ((last-digit (% n 10)))
        (case last-digit
          (1 "st")
          (2 "nd")
          (3 "rd")
          (otherwise "th"))))) n))

and I'd like to be able to use it in format-time-string. Normally, I would look at the source of the function, but this one is defined in the C source code. (I would presume this precludes hooking something onto it, but I stand to be corrected.)

How can I add another format specifier (say, %o) that will apply nth to the appropriate argument?

Desired usage:

(format-time-string "%A, %B %o, %T (%z)" (seconds-to-time 1250553600))

=> "Monday, August 17th, 20:00:00 (-0400)"

Solution

  • Here is what you want to do. Stefan and Drew already gave some important remarks (don't overwrite nth and look at the info-files of emacs-lisp/advising functions).

    (defun ordinal (n)
      "Special day of month format."
      (format
       (concat
        "%d"
        (if (memq n '(11 12 13)) "th"
          (let ((last-digit (% n 10)))
            (case last-digit
              (1 "st")
              (2 "nd")
              (3 "rd")
              (otherwise "th"))))) n))
    
    
    (defadvice format-time-string (before ordinal activate)
      "Add ordinal to %d."
      (let ((day (nth 3 (decode-time (or time (current-time))))))
        (setq format-string
          (replace-regexp-in-string "%o"
                        (ordinal day)
                        format-string))))
    

    Notes:

    1. I did not handle the UNIVERSAL argument

    2. The hack does not work when format-time-string is called from C (as you can read in the manual).