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

1.1k views Asked by At

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)"
3

There are 3 answers

0
Tobias On BEST ANSWER

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).

1
Stefan On

AFAIK you're out of luck: format-time-string does not offer any way to do that.

You might be able to work around this by using something like:

(let ((ti (seconds-to-time 1250553600)))
 (format-time-string (concat "%A, %B " (my-nth (format-time-string "%d" ti)) ", %T (%z)") ti))

This said, I've always been told that "August 17th" is wrong: you're supposed to write "August 17" which is pronounced "August the seventheenth".

One more thing: nth is a predefined core function. Better not overwrite it with your own completely different definition.

0
Drew On

To add to what Stefan said ("You're out of luck") --

format-time-string is a built-in, but you can advise built-ins too. However, since the kind of surgery you want to do would dig into the bowels of the definition (which you cannot do), you would need to in fact replace the definition of format-time-string in the defadvice, i.e., not use ad-do-it at all.

In other words, one way or the other (defun or defadvice) you would need to completely redefine the function, in Lisp. Which is about the same as saying "You're out of luck."