Emacs: xah-fix-datetime πŸš€

By Xah Lee. Date: . Last updated: .

Here's a command that fix datetime under cursor into yyyy-mm-dd format.

put this in your Emacs Init File:

(defun xah-fix-datetime (&optional Begin End)
  "Change timestamp under cursor into a yyyy-mm-dd format.
If there's a text selection, use that as input, else use current line.
Replace the text in selection or current line.

Any β€œday of week”, or β€œtime” info, or any other parts of the string, are discarded.
For example:
 TUESDAY, FEB 15, 2011 05:16 ET β†’ 2011-02-15
 November 28, 1994              β†’ 1994-11-28
 Nov. 28, 1994                  β†’ 1994-11-28
 11/28/1994                     β†’ 1994-11-28
 1994/11/28                     β†’ 1994-11-28
 1994.11.28                     β†’ 1994-11-28
 11.28.1994                     β†’ 1994-11-28

URL `http://xahlee.info/emacs/emacs/elisp_datetime_parser.html'
Version: 2020-09-08 2024-02-13 2024-02-27"
  (interactive)
  (require 'parse-time)
  (let (xp1 xp2 xin xout)
    (if (and Begin End)
        (setq xp1 Begin xp2 End)
      (if (region-active-p)
          (setq xp1 (region-beginning) xp2 (region-end))
        (setq xp1 (line-beginning-position) xp2 (line-end-position))))
    (setq xin (string-trim (buffer-substring-no-properties xp1 xp2)))

    (when (not (string-match "[0-9][0-9]" xin))
      (error "input is probably not a date: %s" xin))
    (setq
     xout
     (cond
      ;; yyyymmdd
      ((string-match "\\([0-9][0-9][0-9][0-9]\\)\\([0-9][0-9]\\)\\([0-9][0-9]\\)" xin)
       (concat
        (match-string 1 xin) "-"
        (match-string 2 xin) "-"
        (match-string 3 xin)))

      ;; yyyy.mm.dd
      ((string-match "\\([0-9][0-9][0-9][0-9]\\)\\.\\([0-9][0-9]\\)\\.\\([0-9][0-9]\\)" xin)
       (concat
        (match-string 1 xin) "-"
        (match-string 2 xin) "-"
        (match-string 3 xin)))

      ;; mm.dd.yyyy
      ((string-match "\\([0-9][0-9]\\)\\.\\([0-9][0-9]\\)\\.\\([0-9][0-9][0-9][0-9]\\)" xin)
       (format "%s-%s-%s"
               (match-string 3 xin)
               (match-string 1 xin)
               (match-string 2 xin)))

      ;; yyyy/mm/dd
      ((string-match "\\([0-9][0-9][0-9][0-9]\\)/\\([0-9][0-9]\\)/\\([0-9][0-9]\\)" xin)
       (concat
        (match-string 1 xin) "-"
        (match-string 2 xin) "-"
        (match-string 3 xin)))

      ;; mm/dd/yyyy
      ((string-match "\\([0-9][0-9]\\)/\\([0-9][0-9]\\)/\\([0-9][0-9][0-9][0-9]\\)" xin)
       (concat
        (match-string 3 xin) "-"
        (match-string 1 xin) "-"
        (match-string 2 xin)))
      ;; m/dd/yyyy
      ((string-match "\\([0-9]\\)/\\([0-9][0-9]\\)/\\([0-9][0-9][0-9][0-9]\\)" xin)
       (concat
        (match-string 3 xin) "-0"
        (match-string 1 xin) "-"
        (match-string 2 xin)))

      ;; USA convention of mm/dd/yy
      ((string-match "\\([0-9][0-9]\\)/\\([0-9][0-9]\\)/\\([0-9][0-9]\\)" xin)
       (concat (format-time-string "%C")
               (match-string 3 xin) "-"
               (match-string 1 xin) "-"
               (match-string 2 xin)))
      ;; USA convention of m/dd/yy
      ((string-match "\\([0-9]\\)/\\([0-9][0-9]\\)/\\([0-9][0-9]\\)" xin)
       (concat (format-time-string "%C")
               (match-string 3 xin) "-0"
               (match-string 1 xin) "-"
               (match-string 2 xin)))

      ;; some ISO 8601. yyyy-mm-ddThh:mm
      ((string-match "\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\)T[0-9][0-9]:[0-9][0-9]" xin)
       (concat
        (match-string 1 xin) "-"
        (match-string 2 xin) "-"
        (match-string 3 xin)))
      ;; some ISO 8601. yyyy-mm-dd
      ((string-match "\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\)" xin)
       (concat
        (match-string 1 xin) "-"
        (match-string 2 xin) "-"
        (match-string 3 xin)))
      ;; some ISO 8601. yyyy-mm
      ((string-match "\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)" xin)
       (concat
        (match-string 1 xin) "-"
        (match-string 2 xin)))

      ;; else
      (t
       (progn
         (setq
          xout
          (let ((xmonthAbbr
                 [["January " "Jan. "]
                  ["February " "Feb. "]
                  ["March " "Mar. "]
                  ["April " "Apr. "]
                  ["May " "May. "]
                  ["June " "Jun. "]
                  ["July " "Jul. "]
                  ["August " "Aug. "]
                  ["September " "Sep. "]
                  ["October " "Oct. "]
                  ["November " "Nov. "]
                  ["December " "Dec. "]]
                 ))
            (with-temp-buffer
              (insert xin)
              (mapc
               (lambda (x)
                 (goto-char (point-min))
                 (while (search-forward (aref x 0) nil t)
                   (replace-match (aref x 1) t t)))
               xmonthAbbr)
              (goto-char (point-min))
              (while (search-forward "1st" nil t) (replace-match "1" t t))
              (goto-char (point-min))
              (while (search-forward "2nd" nil t) (replace-match "2" t t))
              (goto-char (point-min))
              (while (search-forward "3rd" nil t) (replace-match "3" t t))
              (goto-char (point-min))
              (while (search-forward "\\([0-9]\\)th" nil t) (replace-match "\\1" xin))
              (buffer-string))))
         (let (xdateList xyear xmonth xdate xyyyy xmm xdd)
           (setq xdateList (parse-time-string xout)
                 xyear (nth 5 xdateList)
                 xmonth (nth 4 xdateList)
                 xdate (nth 3 xdateList)
                 xyyyy (if xyear (number-to-string xyear) "" )
                 xmm (if xmonth (format "%02d" xmonth) "")
                 xdd (if xdate (format "%02d" xdate) ""))
           (concat xyyyy "-" xmm "-" xdd))))))
    (delete-region xp1 xp2)
    (insert xout)))

(defun xah-fix-datetime-string (Datetime)
  "Return a new string of Datetime in yyyy-mm-dd format.
Other datetime info such as hours, minutes, time zone, are discarded. This function calls `xah-fix-datetime' to do work.

URL `http://xahlee.info/emacs/emacs/elisp_datetime_parser.html'
Version: 2020-09-08"
  (with-temp-buffer
    (insert Datetime)
    (xah-fix-datetime (point-min) (point-max))
    (buffer-substring-no-properties (point-min) (point-max))))

Datetime