p0̷nt1ff's weblog

Julian Date converter in Emacs Lisp

You know that feeling when you just need to know the current Julian date? Wouldn't it be great if Emacs could instantly compute the Julian date from a given Gregorian date? Here's how I did it:

(defun my-int (d)
"Needed for gregorian-date-to-julian-date function below"
  (if (> d 0)
      (floor d))
  (if (= d (floor d))
      d)
  (- (floor d) 1))
  
(defun gregorian-date-to-julian-date (year month day hour min sec)
"Calculate Julian date from Gregorian date"
    (setq is-gregorian t)
    (if (or (< year 1582) (and (= year 1582) (or (< month 10) (and (= month 10) (< day 5)))))
    (setq is-gregorian nil))

    (if (< month 3)
          (progn
            (setq year (- year 1))
            (setq month (+ month 12))))

    (setq b 0)
    
    (if is-gregorian
          (setq a (my-int (/ year 100.0)))
          (setq pre-b (+ a my-int (/ a 4.0)))
          (setq b (- 2 pre-b)))

     (let ((jd (+ (my-int (* 365.25 (+ year 4716)))
                  (my-int (* 30.6001 (+ month 1)))
                  (- day 11)
                  b
                  (- 1524.5))))
       (+ jd (/ hour 24.0) (/ min 24.0 60.0) (/ sec 24.0 60.0 60.0))))

 (defun calculate-and-copy-julian-date-from-selected-text ()
 "Calculate Julian date from the selected text and copy to clipboard."
    (interactive)
    (let* ((selected-text (buffer-substring-no-properties (region-beginning) (region-end)))
           (date-parts (mapcar #'string-to-number (split-string selected-text "[-/ :]+")))
           (year (or (nth 0 date-parts) 0))
           (month (or (nth 1 date-parts) 0))
           (day (or (nth 2 date-parts) 0))
           (hour (or (nth 3 date-parts) 0))
           (min (or (nth 4 date-parts) 0))
           (sec (or (nth 5 date-parts) 0)))
      (when (and year month day)
        (let ((jdn (gregorian-date-to-julian-date year month day hour min sec)))
          (kill-new (number-to-string jdn))
          (message "Julian Date: %.2f (copied to clipboard)" jdn)))))

 (global-set-key (kbd "C-S-j") 'calculate-and-copy-julian-date-from-selected-text)

Now, if you have a date in the format 2023-01-31 19:45, simply select it, then do a C-S-j and you'll have the corresponding Julian Date in the minibuffer and also in your kill ring. As convenient as it gets!


Recent posts