I'm trying to use #malliexperimentaltime
Here is what I have
(ns foobar.core
(:require [malli.core :as m]
[malli.registry :as mr]
[malli.experimental.time :as met]))
;; This should add the malli.experimental.time schemas
(mr/set-default-registry!
(mr/composite-registry
(m/default-schemas)
(met/schemas)))
So, I would expect one of those things to be truthy, but none is:
(m/validate :time/local-date "2024-01-01")
(m/validate [:time/local-date] "2024-01-01")
(m/validate [:time/local-date {:pattern "yyyy-mm-dd"}] "2024-01-01")
(m/validate [:time/local-date {:pattern "yyyy-MM-dd"}] "2024-01-01")
(m/validate [:time/local-date {:pattern "YYYY-MM-DD"}] "2024-01-01")
What am I missing here ?
The doc also mentions a "transformation" feature, is that required here ? #transformation---malliexperimentaltimetransform
I'm trying to use https://github/metosin/malli?tab=readme-ov-file#malliexperimentaltime
Here is what I have
(ns foobar.core
(:require [malli.core :as m]
[malli.registry :as mr]
[malli.experimental.time :as met]))
;; This should add the malli.experimental.time schemas
(mr/set-default-registry!
(mr/composite-registry
(m/default-schemas)
(met/schemas)))
So, I would expect one of those things to be truthy, but none is:
(m/validate :time/local-date "2024-01-01")
(m/validate [:time/local-date] "2024-01-01")
(m/validate [:time/local-date {:pattern "yyyy-mm-dd"}] "2024-01-01")
(m/validate [:time/local-date {:pattern "yyyy-MM-dd"}] "2024-01-01")
(m/validate [:time/local-date {:pattern "YYYY-MM-DD"}] "2024-01-01")
What am I missing here ?
The doc also mentions a "transformation" feature, is that required here ? https://github/metosin/malli?tab=readme-ov-file#transformation---malliexperimentaltimetransform
Share Improve this question asked Mar 10 at 22:02 phtrivierphtrivier 13.4k9 gold badges52 silver badges82 bronze badges2 Answers
Reset to default 0I installed it and found out, you fot to parse your string to a `java.time.LocalDate` object:
(ns malli-test.main
(:require [malli.core :as m]
[malli.registry :as mr]
[malli.experimental.time :as met]))
;; Register the experimental time schemas
(mr/set-default-registry!
(mr/composite-registry
(m/default-schemas)
(met/schemas)))
;; Testing time validation
(defn test-time-validation []
(println "Test results:")
(println (m/validate :time/local-date (java.time.LocalDate/parse "2024-01-01"))) ; Expected: true
(println (m/validate [:time/local-date] (java.time.LocalDate/parse "2024-01-01"))) ; Expected: true
(println (m/validate [:time/local-date {:pattern "yyyy-mm-dd"}] (java.time.LocalDate/parse "2024-01-01"))) ; Expected: true
(println (m/validate [:time/local-date {:pattern "yyyy-MM-dd"}] (java.time.LocalDate/parse "2024-01-01"))) ; Expected: true
(println (m/validate [:time/local-date {:pattern "YYYY-MM-DD"}] (java.time.LocalDate/parse "2024-01-01")))) ; Expected: true
(test-time-validation) ;; this will print all `true`!
Since java.time
is already in the standard packages, you don't need to require
anything extra.
Use custom predicate functions to test for validity
If your aim is to test a date string for validity, then I would use custom predicate functions which then could be used with malli
:
(ns malli-test.main
(:require [malli.core :as m]
[malli.registry :as mr]
[malli.experimental.time :as met])
(:import [java.time LocalDate]
[java.time.format DateTimeParseException]))
;; Register the experimental time schemas
(mr/set-default-registry!
(mr/composite-registry
(m/default-schemas)
(met/schemas)))
;; Build your custom predicate function to test for validity of a time string
(defn valid-date-string? [date-str]
(try
(LocalDate/parse date-str)
true ;; successfully parsed, otherwise:
(catch DateTimeParseException _ false)))
(valid-date-string? "2025-01-01") ; => true
(valid-date-string? "2023-02-29") ; => false
;; (LocalDate/parse "2025-01-01")
;; Define a Malli schema using this custom predicate
(def DateSchema [:and string? [:fn valid-date-string?]])
;; Test like this:
(m/validate DateSchema "2025-01-01") ; => true
(m/validate DateSchema "2025-13-99") ; => false (invalid date)
(m/validate DateSchema "not-a-date") ; => false
(m/validate DateSchema "2024-02-29") ; => true (leap year)
(m/validate DateSchema "2023-02-29") ; => false (not a leap year)
Thanks to @gwang-jim-kim for the help, but I found at what I was missing:
I was confusing the role of
m/validate
,m/decode
andm/coerce
m/validate
check that a value conforms to a schemam/decode
will use a transformer to turn a value into something conforming to the schema, but silently failm/coerce
will do the same, but raise
In my case, I want to turn the input string into a date, so I was needing
m/coerce
There are already built-in transformers to pass to
m/coerce
in themalli.experimental.time.transformer
namespaceHowever, for some reason, my project was depending on
.clojure/clojure "1.10.1"
, and this caused an error when loading the workspace (becausemath
was not available.) (This is fixed by depending on more recent version (eg "1.11.1"))Also, I was using the wrong parsing pattern sometimes :facepalm:...
So, in the end, this does what I want:
(ns flight.core
(:require [malli.core :as m]
[malli.registry :as mr]
[malli.experimental.time :as met]
[malli.experimental.time.transform :as mett]))
(mr/set-default-registry!
(mr/composite-registry
(m/default-schemas)
(met/schemas)))
(def schema [:time/local-date {:pattern "yyyy-MM-dd"}] )
(m/validate schema "2024-01-01") ;;=> false, the string is not a LocalDate
(m/coerce schema "2024-01-01" mett/time-transformer) ;;=> this returns a java.time.LocalDate
(m/decode schema "2024-01-01x" mett/time-transformer) ;;=> this returns the string "2024-01-01x" because decode silently ignores transformation that raise error
(m/coerce schema "2024-01-01x" mett/time-transformer) ;;=> this raises an error
(m/validate schema (m/decode schema "2024-01-01x" mett/time-transformer)) ;;=> this returns false
(m/validate schema (m/decode schema "2024-01-01" mett/time-transformer)) ;;=> this returns true