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

      )))
Onner Irotsab
  • 431
  • 2
  • 9
  • You can replace the many nested `if` expressions with a single flat [`cond`](https://www.gnu.org/software/emacs/manual/html_node/elisp/Conditionals.html) or [`pcase`](https://www.gnu.org/software/emacs/manual/html_node/elisp/pcase-Macro.html). – Basil Apr 14 '21 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 Apr 16 '21 at 19:51

1 Answers1

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.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • 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 Apr 16 '21 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 Apr 16 '21 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 Apr 17 '21 at 15:42