Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check leap years with Clojure

Tags:

clojure

I'm stuck using the and operator, how can you test for multiple conditions. I am very close but am stuck to solving this with clojure.

(defn leap [year] (cond (and (zero? (rem year 4)) (zero? (rem year 100))) true :else false))

Thank you for your help.

like image 342
reZach Avatar asked Aug 13 '26 21:08

reZach


2 Answers

you are using and properly, but your logic is wrong and should not be using and

(defn leap
  [year]
  (cond (zero? (mod year 400)) true
        (zero? (mod year 100)) false
        (zero? (mod year 4)) true
        :default false))

(this is according to the rules for leap years in the Gregorian Calendar as listed on the wikipedia page for Leap Year).

I have avoided any usage of nested logic operators because the purpose of cond is to simplify what would otherwise be a complex nested conditional into a linear sequence of choices where the first appropriate choice is selected.

Ideally one should be using a library like clj-time for any time / date logic, because these things are always much harder than anticipated to do properly and generally.

Additionally, one could use condp, though in this case I think it obfuscates more than it clarifies:

(condp #(zero? (mod %2 %))
    year
  400 true
  100 false
  4 true
  false)
like image 163
noisesmith Avatar answered Aug 16 '26 17:08

noisesmith


Don’t reinvent the wheel, use clj-time’s number-of-days-in-the-month:

(require 'clj-time.core)

(defn leap-year? [year]
  (= 29 (clj-time.core/number-of-days-in-the-month year 2)))

or alternatively:

(defn leap-year? [year]
  (= 366 (clj-time.core/in-days
           (clj-time.core/interval (clj-time.core/date-time year 1 1)
                                   (clj-time.core/date-time (+ 1 year) 1 1)))))
like image 38
Andrew Marshall Avatar answered Aug 16 '26 16:08

Andrew Marshall