period.bend source
period.bend on the hub · documented module
import Baseimport ./date.bend as Dtype Period.Error is Data: OutOfRange{}type Period is Data: Period{years: U32, months: U32, days: U32}def Period.from.y( +years: U32, +extra: U32, +months: U32, +days: U32, ok: Bool) -> Result<&2, &2, Period.Error, Period>: match ok: case False{}: Fail{OutOfRange{}} case True{}: Done{Period{U32.add(years, extra), months, days}}def Period.from( +years: U32, +months: U32, +days: U32) -> Result<&2, &2, Period.Error, Period>: +extra = U32.div(months, 12) Period.from.y( years, extra, U32.mod(months, 12), days, U32.is_le(extra, U32.sub(U32.not(0), years)) )def Period.add_to.days( r: Result<&2, &2, D.Date.Error, D.Date>, pd: U32) -> Result<&2, &2, D.Date.Error, D.Date>: match r: case Fail{e}: Fail{e} case Done{date}: D.Date.add_days(date, pd)def Period.add_to.from( +y: U32, +m: U32, +d: U32, +pd: U32) -> Result<&2, &2, D.Date.Error, D.Date>: Period.add_to.days(D.Date.from(y, m, d), pd)def Period.add_to.day( +y: U32, +m: U32, +d: U32, +pd: U32, +dim: U32, le: Bool) -> Result<&2, &2, D.Date.Error, D.Date>: match le: case True{}: Period.add_to.from(y, m, d, pd) case False{}: Period.add_to.from(y, m, dim, pd)def Period.add_to.dim( +y: U32, +m: U32, +d: U32, +pd: U32, dimr: Maybe<&2, U32>) -> Result<&2, &2, D.Date.Error, D.Date>: match dimr: case None{}: Fail{D.OutOfRange{}} case Some{+dim}: Period.add_to.day(y, m, d, pd, dim, U32.is_le(d, dim))def Period.add_to.y3( +y: U32, +m: U32, +d: U32, +pd: U32, ok: Bool) -> Result<&2, &2, D.Date.Error, D.Date>: match ok: case False{}: Fail{D.OutOfRange{}} case True{}: Period.add_to.dim(y, m, d, pd, D.Date.dim(m, D.Date.leap(y)))def Period.add_to.y2( +y: U32, +m: U32, +d: U32, +pd: U32) -> Result<&2, &2, D.Date.Error, D.Date>: Period.add_to.y3(y, m, d, pd, Bool.and(U32.is_ge(y, 1), U32.is_le(y, 9999)))def Period.add_to.mc( +y: U32, +m: U32, +d: U32, +pd: U32, ge: Bool) -> Result<&2, &2, D.Date.Error, D.Date>: match ge: case False{}: Period.add_to.y2(y, m, d, pd) case True{}: Period.add_to.y2(U32.add(y, 1), U32.sub(m, 12), d, pd)def Period.add_to.ya( +dy: U32, +py: U32, +dm: U32, +pm: U32, +dd: U32, +pd: U32, ok: Bool) -> Result<&2, &2, D.Date.Error, D.Date>: match ok: case False{}: Fail{D.OutOfRange{}} case True{}: +y = U32.add(dy, py) +m = U32.add(dm, pm) Period.add_to.mc(y, m, dd, pd, U32.is_gt(m, 12))def Period.add_to.go( date: D.Date, p: Period) -> Result<&2, &2, D.Date.Error, D.Date>: match date p: case D.Date{+dy, +dm, +dd} Period{+py, +pm, +pd}: Period.add_to.ya( dy, py, dm, pm, dd, pd, U32.is_le(py, U32.sub(U32.not(0), dy)) )def Period.add_to( p: Period, date: D.Date) -> Result<&2, &2, D.Date.Error, D.Date>: Period.add_to.go(date, p)def Period.emonth(+y: U32, +m: U32) -> U32: U32.add(U32.mul(y, 12), m)def Period.between.ms.from( +end: D.Date, +tm: U32, r: Result<&2, &2, D.Date.Error, D.Date>) -> Result<&2, &2, Period.Error, Period>: match r: case Fail{_}: Fail{OutOfRange{}} case Done{start2}: Period.from( U32.div(tm, 12), U32.mod(tm, 12), U32.sub(D.Date.to_days(end), D.Date.to_days(start2)) )def Period.between.ms.add( +start: D.Date, +end: D.Date, +tm: U32, rp: Result<&2, &2, Period.Error, Period>) -> Result<&2, &2, Period.Error, Period>: match rp: case Fail{_}: Fail{OutOfRange{}} case Done{pM}: Period.between.ms.from(end, tm, Period.add_to(pM, start))def Period.between.ms( +start: D.Date, +end: D.Date, +tm: U32) -> Result<&2, &2, Period.Error, Period>: Period.between.ms.add(start, end, tm, Period.from(0, tm, 0))def Period.between.day( start: D.Date, end: D.Date, sm: U32, em: U32, borrow: Bool) -> Result<&2, &2, Period.Error, Period>: match borrow: case True{}: Period.between.ms(start, end, U32.sub(U32.sub(em, sm), 1)) case False{}: Period.between.ms(start, end, U32.sub(em, sm))def Period.between.go( +start: D.Date, +end: D.Date) -> Result<&2, &2, Period.Error, Period>: match start end: case D.Date{+sy, +sm, +sd} D.Date{+ey, +em, +ed}: Period.between.day( start, end, Period.emonth(sy, sm), Period.emonth(ey, em), U32.is_lt(ed, sd) )def Period.between.ord( start: D.Date, end: D.Date, lt: Bool) -> Result<&2, &2, Period.Error, Period>: match lt: case True{}: Fail{OutOfRange{}} case False{}: Period.between.go(start, end)def Period.between( +start: D.Date, +end: D.Date) -> Result<&2, &2, Period.Error, Period>: Period.between.ord(start, end, D.Date.is_lt(end, start))