1

I am interested in inserting custom dates using the calendar, I found Insert date using a calendar which turned out to be quite useful. Org calendar : change date language? seems to have no effect (I would also like to avoid setting the variable via seq)

While this code works fine for English dates.

(defun my/org-insert-date-english ()
  "Insert a date at point using `org-read-date' with its optional argument
of TO-TIME so that the user can customize the date format more easily."
  (interactive)
  (require 'org)
  (let ((time (org-read-date nil 'to-time nil "Date:  ")))
    (insert (format-time-string "(W%W) (%a) %d %b %Y"
                                time))))

;; Inserts: (W19) (Thu) 16 May 2019

I was trying to modify it to get it work to insert dates in a different laguage than english.

My modifications below don't work but I am not sure why, could someone pin point what am I doing wrong?

(defun my/org-insert-date-german ()
  "Insert a date at point using `org-read-date' with its optional argument
of TO-TIME so that the user can customize the date format more easily."
  (interactive)
  (require 'org)
  (letf ((time (org-read-date nil 'to-time nil "Date:  "))
         (calendar-week-start-day 1)
         (calendar-day-name-array ["Montag" "Dienstag" "Mittwoch" "Donnerstag"
                                   "Freitag" "Samstag" "Sonntag"])
         (calendar-month-name-array ["Januar" "Februar" "März" "April" "Mai" "Juni"
                                     "Juli" "August" "September" "Oktober" "November"
                                     "Dezember"]))
    (insert (format-time-string "(KW%W) (%a) %d. %b %Y"
                                time))))

;; Inserts: (KW19) (Thu) 16. May 2019
;; Desired: (KW19) (Donnerstag) 16. Mai 2019

Notes: - Using Emacs 26.2

Cesc
  • 289
  • 1
  • 11
  • I don't think `format-time-string` works like that. Seems probable that it uses C functions that work based on the current locale. – Willy Lee May 16 '19 at 19:12
  • That's the case, in the docs I could see `format-time-string is a built-in function in ‘C source code’.` but I couldn't come up with any workaround but `jagrg` answer does the trick – Cesc May 17 '19 at 07:51

1 Answers1

2

What you're trying to do won't work with format-time-string. Here's a time string formatter using calendar-* functions which you can use in place of format-time-string. I haven't thought about how the offsetting is done with calendar-week-start-day so for now you have to start the name array with "Sonntag".

(defun calendar-format-time-string (format-string time)
  (let* ((date (org-date-to-gregorian (format-time-string "%F" time)))
         (week (car (calendar-iso-from-absolute (time-to-days time))))
         (week-day (calendar-day-name date))
         (day (calendar-extract-day date))
         (month (calendar-month-name (calendar-extract-month date)))
         (year (calendar-extract-year date))
         (specs (format-spec-make ?W week ?a week-day ?d day ?b month ?Y year)))
    (format-spec format-string specs)))

Here's a more flexible approach which formats %B (January), %b (Jan), %A (Sunday), and %a (Sun) using calendar functions. All other specs are passed to format-time-string.

(defun calendar-format-time-string (format-string time)
  (let* ((case-fold-search nil)
         (date (org-date-to-gregorian (format-time-string "%F" time)))
         (week (calendar-day-name date))
         (week-abbrev (calendar-day-name date t))
         (month (calendar-month-name (calendar-extract-month date)))
         (month-abbrev (calendar-month-name (calendar-extract-month date) t))
         (specs (format-spec-make ?A week
                                  ?a week-abbrev
                                  ?B month
                                  ?b month-abbrev))
         time-string)
    (with-temp-buffer
      (insert format-string)
      (goto-char (point-min))
      (while (re-search-forward (mapconcat (lambda (char)
                                             (concat "%" (char-to-string char)))
                                           (mapcar #'car specs) "\\|")
                                 nil t)
         (let ((spec (format-spec (match-string 0) specs)))
           (delete-char -2)
           (insert spec)))
       (setq time-string (buffer-substring (point-min) (point-max))))
     (format-time-string time-string time)))

BTW you can also use format-time-string directly by changing the time locale:

  1. $ sudo emacs /etc/locale.gen
  2. uncomment the de_DE.UTF-8 UTF-8 line and save the file
  3. $ sudo locale-gen
  4. M-x set-locale-environment RET de_DE.UTF-8 RET
  5. restart emacs

Now set system-time-locale as a local variable and you're done:

(let ((system-time-locale "de_DE.UTF-8")
      (time (org-read-date nil 'to-time nil "Date:  ")))
  (insert (format-time-string "(KW%W) (%A) %d. %B %Y" time)))

;; => (KW19) (Samstag) 18. Mai 2019
jagrg
  • 3,824
  • 4
  • 19