(.require [library [lux (.except) [abstract [monad (.only do)] [equivalence (.only Equivalence)]] [control ["<>" parser] ["[0]" try (.only Try)] ["[0]" exception (.only Exception)]] [data ["[0]" text ["%" \\format] ["<[1]>" \\parser (.only Parser)]]] [math [number ["n" nat] ["i" int]]] [meta [type ["[0]" nominal (.except def)]]] [world [time ["[0]" date (.use "[1]#[0]" equivalence)] ["[0]" year] ["[0]" month]]]]]) (def .public (pad value) (-> Nat Text) (if (n.< 10 value) (%.format "0" (%.nat value)) (%.nat value))) (def min_year +1,000) (def max_year +9,999) (exception.def .public (year_is_out_of_range year) (Exception year.Year) (exception.report (list ["Minimum" (%.int ..min_year)] ["Maximum" (%.int ..max_year)] ["Year" (%.int (year.value year))]))) (nominal.def .public Date date.Date (def .public epoch Date (abstraction date.epoch)) (def .public (date raw) (-> date.Date (Try Date)) (let [year (|> raw date.year year.value)] (if (or (i.< ..min_year year) (i.> ..max_year year)) (exception.except ..year_is_out_of_range [(date.year raw)]) {try.#Success (abstraction raw)}))) (def .public value (-> Date date.Date) (|>> representation)) (def .public equivalence (Equivalence Date) (implementation (def (= reference subject) (date#= (representation reference) (representation subject))))) (def .public (format value) (%.Format Date) (%.format (|> value representation date.year year.value .nat %.nat) (|> value representation date.month month.number ..pad) (|> value representation date.day_of_month ..pad))) (def .public parser (Parser Date) (do <>.monad [year (<>.codec n.decimal (.exactly 4 .decimal)) year (<>.of_try (year.year (.int year))) month (<>.codec n.decimal (.exactly 2 .decimal)) month (<>.of_try (month.by_number month)) day_of_month (<>.codec n.decimal (.exactly 2 .decimal)) date (<>.of_try (date.date year month day_of_month))] (in (abstraction date)))))