2

I have a LaTeX package declared with a date:

\usepackage{foo}[=2021-04-01]

and I need to check if this date is before or after "2021-03-01".

Is there a way to compare dates, like (if (< date1 date0) ... )?

Raw solution

Thanks to @Drew's answer I have found this solution:

(defun myfunc ()
  (interactive)

  (goto-char (point-min))
  (when (re-search-forward "\\\\usepackage{foo}\\[=\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)\\]" nil t)
    (let* ((year (match-string 1))
           (month-num (match-string 2))
           (day (match-string 3))
           (month)
           (t0)
           (t1))

      (if (string-equal month-num "01")
          (setq month "jan")
        (if (string-equal month-num "02")
            (setq month "feb")
          (if (string-equal month-num "03")
              (setq month "mar")
            (if (string-equal month-num "04")
                (setq month "apr")
              (if (string-equal month-num "05")
                  (setq month "may")
                (if (string-equal month-num "06")
                    (setq month "jun")
                  (if (string-equal month-num "07")
                      (setq month "jul")
                    (if (string-equal month-num "08")
                        (setq month "aug")
                      (if (string-equal month-num "09")
                          (setq month "sep")
                        (if (string-equal month-num "10")
                            (setq month "oct")
                          (if (string-equal month-num "11")
                              (setq month "nov")
                            (if (string-equal month-num "12")
                                (setq month "dec")))))))))))))

      (setq t0 (date-to-time "01 mar 2021 00.00.00"))
      (setq t1 (date-to-time (concat day
                                     " "
                                     month
                                     " "
                                     year
                                     " 00.00.00")))
      (if (time-less-p t1 t0)
          (insert "foo")
        (if (time-less-p t0 t1)
            (insert "bar")))

      )))

I can't figure out how to manipulate date-to-time argument: how can I simply use "2021-01-01" as date format?

I have read about (format-time-string "%Y-%m-%d"), but I don't understand how to use it.

Raw Solution Update

For the sake of completeness:

(cond
 ((string= month-num "01")
  (setq month "jan"))
 ((string= month-num "02")
  (setq month "feb"))
 ((string= month-num "03")
  (setq month "mar"))
 ((string= month-num "04")
  (setq month "apr"))
 ((string= month-num "05")
  (setq month "may"))
 ((string= month-num "06")
  (setq month "jun"))
 ((string= month-num "07")
  (setq month "jul"))
 ((string= month-num "08")
  (setq month "aug"))
 ((string= month-num "09")
  (setq month "sep"))
 ((string= month-num "10")
  (setq month "oct"))
 ((string= month-num "11")
  (setq month "nov"))
 ((string= month-num "12")
  (setq month "dec")))

(I don't know about pcase.)

Final Solution

Putting together all your suggestions, I got the following solution:

(defun myfunc ()
  (interactive)

  (goto-char (point-min))
  (when (re-search-forward "\\\\usepackage{foo}\\[=\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)\\]" nil t)
    (let* ((release (concat (match-string 1)
                            "-"
                            (match-string 2)
                            "-"
                            (match-string 3)
                            " 00:00:00"))
           (t0)
           (t1))

      (setq t0 (date-to-time "2021-03-01 00:00:00"))
      (setq t1 (date-to-time release))

      (if (time-less-p t1 t0)
          (insert "foo")
        (if (time-less-p t0 t1)
            (insert "bar")))

      )))
2
  • You can replace the many nested if expressions with a single flat cond or pcase.
    – Basil
    Commented Apr 14, 2021 at 18:24
  • You should just be able to parse the date in the format you already have with some minor modification with (parse-time-string (format "%s 00:00:00 Z" "2021-04-16")) - I used a string in the example to demonstrate but you could just store your whole regex match in a variable and use that. However, see my comment on the answer below about a potential issue with time-less-p.
    – kfoley
    Commented Apr 16, 2021 at 19:51

1 Answer 1

5

Convert the date strings to time values, then use time-less-p to compare the time values.

C-h f time-less-p:

time-less-p is a built-in function in ‘C source code’.

(time-less-p T1 T2)

Return non-nil if time value T1 is earlier than time value T2.

A nil value for either argument stands for the current time. See current-time-string for the various forms of a time value.

See also function date-to-time:

date-to-time is an autoloaded compiled Lisp function in time-date.el.

(date-to-time DATE)

Parse a string DATE that represents a date-time and return a time value.

DATE should be in one of the forms recognized by parse-time-string. If DATE lacks timezone information, GMT is assumed.

For example, this returns t, and with the args in the opposite order it returns nil.

(time-less-p (date-to-time "2021-04-15 13:00:00")
             (date-to-time "2021-04-16 12:00:00")) 

See the Elisp manual, nodes Time Calculations and Time Parsing.

3
  • I may be misunderstanding something but it looks like time-less-p only compares the time elements of datetime's. So comparing 2021-04-16 12:00:00 and 2021-04-15 13:00:00 would indicate the latter is greater, because 13 > 12, ignoring the fact that it's a day before.
    – kfoley
    Commented Apr 16, 2021 at 19:46
  • 1
    @kfoley: I don't see that. (time-less-p (date-to-time "2021-04-15 13:00:00") (date-to-time "2021-04-16 12:00:00")) returns t, and in the opposite order returns nil.
    – Drew
    Commented Apr 16, 2021 at 22:23
  • You're correct, I was using time-less-p with the result of parse-time-string instead of date-to-time
    – kfoley
    Commented Apr 17, 2021 at 15:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.