~/bend-docscommunity

date.bend source

date.bend on the hub · documented module

import Basetype Date.Error is Data:  InvalidDate{year: U32, month: U32, day: U32}  OutOfRange{}type Date is Data:  Date{year: U32, month: U32, day: U32}def Date.leap100(+y: U32, d100: Bool) -> Bool:  match d100:    case False{}:      True{}    case True{}:      U32.is_eq(U32.mod(y, 400), 0)def Date.leap4(+y: U32, d4: Bool) -> Bool:  match d4:    case False{}:      False{}    case True{}:      Date.leap100(y, U32.is_eq(U32.mod(y, 100), 0))def Date.leap(+y: U32) -> Bool:  Date.leap4(y, U32.is_eq(U32.mod(y, 4), 0))def Date.dim.feb(leap: Bool) -> U32:  match leap:    case True{}:      29    case False{}:      28def Date.is_31(+m: U32) -> Bool:  Bool.or(    U32.is_eq(m, 1),    Bool.or(      U32.is_eq(m, 3),      Bool.or(        U32.is_eq(m, 5),        Bool.or(          U32.is_eq(m, 7),          Bool.or(            U32.is_eq(m, 8),            Bool.or(U32.is_eq(m, 10), U32.is_eq(m, 12))          )        )      )    )  )def Date.is_30(+m: U32) -> Bool:  Bool.or(    U32.is_eq(m, 4),    Bool.or(U32.is_eq(m, 6), Bool.or(U32.is_eq(m, 9), U32.is_eq(m, 11)))  )def Date.dim.rest3(m: U32, d30: Bool) -> Maybe<&2, U32>:  match d30:    case True{}:      Some{30}    case False{}:      None{}def Date.dim.rest2(+m: U32, d31: Bool) -> Maybe<&2, U32>:  match d31:    case True{}:      Some{31}    case False{}:      Date.dim.rest3(m, Date.is_30(m))def Date.dim.rest(+m: U32) -> Maybe<&2, U32>:  Date.dim.rest2(m, Date.is_31(m))def Date.dim.m(+m: U32, leap: Bool, feb: Bool) -> Maybe<&2, U32>:  match feb:    case True{}:      Some{Date.dim.feb(leap)}    case False{}:      Date.dim.rest(m)def Date.dim(+m: U32, leap: Bool) -> Maybe<&2, U32>:  Date.dim.m(m, leap, U32.is_eq(m, 2))def Date.from.day2(  +y: U32, +m: U32, +d: U32, ok: Bool) -> Result<&2, &2, Date.Error, Date>:  match ok:    case False{}:      Fail{InvalidDate{y, m, d}}    case True{}:      Done{Date{y, m, d}}def Date.from.day(  +y: U32, +m: U32, +d: U32, dim: U32) -> Result<&2, &2, Date.Error, Date>:  Date.from.day2(    y, m, d, Bool.and(U32.is_ge(d, 1), U32.is_le(d, dim))  )def Date.from.dim(  +y: U32, +m: U32, +d: U32, dim: Maybe<&2, U32>) -> Result<&2, &2, Date.Error, Date>:  match dim:    case None{}:      Fail{InvalidDate{y, m, d}}    case Some{n}:      Date.from.day(y, m, d, n)def Date.from.y(  +y: U32, +m: U32, +d: U32, ok: Bool) -> Result<&2, &2, Date.Error, Date>:  match ok:    case False{}:      Fail{InvalidDate{y, m, d}}    case True{}:      Date.from.dim(y, m, d, Date.dim(m, Date.leap(y)))def Date.from(  +y: U32, +m: U32, +d: U32) -> Result<&2, &2, Date.Error, Date>:  Date.from.y(y, m, d, Bool.and(U32.is_ge(y, 1), U32.is_le(y, 9999)))def Date.dim_of.go(dim: Maybe<&2, U32>) -> Result<&2, &2, Date.Error, U32>:  match dim:    case None{}:      Fail{OutOfRange{}}    case Some{+n}:      Done{n}def Date.dim_of(+y: U32, +m: U32) -> Result<&2, &2, Date.Error, U32>:  Date.dim_of.go(Date.dim(m, Date.leap(y)))def Date.days_in_month(date: Date) -> Result<&2, &2, Date.Error, U32>:  match date:    case Date{+y, +m, _}:      Date.dim_of(y, m)def Date.end_of_month.go(  +y: U32, +m: U32, r: Result<&2, &2, Date.Error, U32>) -> Result<&2, &2, Date.Error, Date>:  match r:    case Fail{e}:      Fail{e}    case Done{dim}:      Done{Date{y, m, dim}}def Date.end_of_month(date: Date) -> Result<&2, &2, Date.Error, Date>:  match date:    case Date{+y, +m, _}:      Date.end_of_month.go(y, m, Date.dim_of(y, m))def Date.start_of_month(date: Date) -> Date:  match date:    case Date{y, m, _}:      Date{y, m, 1}def Date.start_of_year(date: Date) -> Date:  match date:    case Date{y, _, _}:      Date{y, 1, 1}def Date.end_of_year(date: Date) -> Date:  match date:    case Date{y, _, _}:      Date{y, 12, 31}def Date.with_day(date: Date, d: U32) -> Result<&2, &2, Date.Error, Date>:  match date:    case Date{+y, +m, _}:      Date.from(y, m, d)def Date.with_month(date: Date, m: U32) -> Result<&2, &2, Date.Error, Date>:  match date:    case Date{+y, _, +d}:      Date.from(y, m, d)def Date.with_year(date: Date, y: U32) -> Result<&2, &2, Date.Error, Date>:  match date:    case Date{_, +m, +d}:      Date.from(y, m, d)def Date.y_adj(y: U32, jf: Bool) -> U32:  match jf:    case True{}:      U32.sub(y, 1)    case False{}:      ydef Date.mp(m: U32, jf: Bool) -> U32:  match jf:    case True{}:      U32.add(m, 9)    case False{}:      U32.sub(m, 3)def Date.doy(+m: U32, +d: U32, jf: Bool) -> U32:  U32.sub(U32.add(U32.div(U32.add(U32.mul(153, Date.mp(m, jf)), 2), 5), d), 1)def Date.to_days.era(+era: U32, +yoe: U32, doy: U32) -> U32:  U32.add(    U32.mul(era, 146097),    U32.add(      U32.sub(        U32.add(U32.mul(yoe, 365), U32.div(yoe, 4)),        U32.div(yoe, 100)      ),      doy    )  )def Date.to_days.yoe(+ya: U32, doy: U32) -> U32:  Date.to_days.era(    U32.div(ya, 400),    U32.sub(ya, U32.mul(U32.div(ya, 400), 400)),    doy  )def Date.to_days.parts(+y: U32, +m: U32, +d: U32) -> U32:  Date.to_days.yoe(Date.y_adj(y, U32.is_le(m, 2)), Date.doy(m, d, U32.is_le(m, 2)))def Date.to_days(date: Date) -> U32:  match date:    case Date{y, m, d}:      Date.to_days.parts(y, m, d)def Date.is_eq(a: Date, b: Date) -> Bool:  match a b:    case Date{+y1, +m1, +d1} Date{+y2, +m2, +d2}:      Bool.and(        U32.is_eq(y1, y2),        Bool.and(U32.is_eq(m1, m2), U32.is_eq(d1, d2))      )def Date.is_lt(a: Date, b: Date) -> Bool:  U32.is_lt(Date.to_days(a), Date.to_days(b))def Date.is_gt(a: Date, b: Date) -> Bool:  Date.is_lt(b, a)def Date.is_le(a: Date, b: Date) -> Bool:  Bool.not(Date.is_lt(b, a))def Date.is_ge(a: Date, b: Date) -> Bool:  Bool.not(Date.is_lt(a, b))def Date.from_days.doe(+z: U32, era: U32) -> U32:  U32.sub(z, U32.mul(era, 146097))def Date.from_days.yoe(+doe: U32) -> U32:  U32.div(    U32.sub(      U32.add(U32.sub(doe, U32.div(doe, 1460)), U32.div(doe, 36524)),      U32.div(doe, 146096)    ),    365  )def Date.from_days.doy(+doe: U32, +yoe: U32) -> U32:  U32.sub(    doe,    U32.sub(      U32.add(U32.mul(365, yoe), U32.div(yoe, 4)),      U32.div(yoe, 100)    )  )def Date.from_days.mp(+doy: U32) -> U32:  U32.div(U32.add(U32.mul(5, doy), 2), 153)def Date.from_days.day(+doy: U32, +mp: U32) -> U32:  U32.add(U32.sub(doy, U32.div(U32.add(U32.mul(153, mp), 2), 5)), 1)def Date.from_days.month(+mp: U32, lt: Bool) -> U32:  match lt:    case True{}:      U32.add(mp, 3)    case False{}:      U32.sub(mp, 9)def Date.from_days.year(+y: U32, jan: Bool) -> U32:  match jan:    case True{}:      U32.add(y, 1)    case False{}:      ydef Date.from_days.parts(+z: U32) -> Result<&2, &2, Date.Error, Date>:  +era = U32.div(z, 146097)  +doe = Date.from_days.doe(z, era)  +yoe = Date.from_days.yoe(doe)  +doy = Date.from_days.doy(doe, yoe)  +mp = Date.from_days.mp(doy)  +m = Date.from_days.month(mp, U32.is_lt(mp, 10))  Date.from(    Date.from_days.year(U32.add(yoe, U32.mul(era, 400)), U32.is_le(m, 2)),    m,    Date.from_days.day(doy, mp)  )def Date.from_days(z: U32) -> Result<&2, &2, Date.Error, Date>:  Date.from_days.parts(z)type Weekday is Data:  Mon{}  Tue{}  Wed{}  Thu{}  Fri{}  Sat{}  Sun{}def Date.weekday.n6(+n: U32, is6: Bool) -> Weekday:  match is6:    case True{}:      Sun{}    case False{}:      Sat{}def Date.weekday.n5(+n: U32, is5: Bool) -> Weekday:  match is5:    case True{}:      Sat{}    case False{}:      Date.weekday.n6(n, U32.is_eq(n, 6))def Date.weekday.n4(+n: U32, is4: Bool) -> Weekday:  match is4:    case True{}:      Fri{}    case False{}:      Date.weekday.n5(n, U32.is_eq(n, 5))def Date.weekday.n3(+n: U32, is3: Bool) -> Weekday:  match is3:    case True{}:      Thu{}    case False{}:      Date.weekday.n4(n, U32.is_eq(n, 4))def Date.weekday.n2(+n: U32, is2: Bool) -> Weekday:  match is2:    case True{}:      Wed{}    case False{}:      Date.weekday.n3(n, U32.is_eq(n, 3))def Date.weekday.n1(+n: U32, is1: Bool) -> Weekday:  match is1:    case True{}:      Tue{}    case False{}:      Date.weekday.n2(n, U32.is_eq(n, 2))def Date.weekday.n(+n: U32) -> Weekday:  Date.weekday.n1(n, U32.is_eq(n, 1))def Date.weekday.zero(+n: U32, z: Bool) -> Weekday:  match z:    case True{}:      Mon{}    case False{}:      Date.weekday.n(n)def Date.weekday(date: Date) -> Weekday:  +n = U32.mod(U32.add(Date.to_days(date), 2), 7)  Date.weekday.zero(n, U32.is_eq(n, 0))def Date.add_ov(+z: U32, n: U32, ok: Bool) -> Result<&2, &2, Date.Error, Date>:  match ok:    case False{}:      Fail{OutOfRange{}}    case True{}:      Date.from_days(U32.add(z, n))def Date.add_days(+date: Date, +n: U32) -> Result<&2, &2, Date.Error, Date>:  +z = Date.to_days(date)  Date.add_ov(z, n, U32.is_le(n, U32.sub(U32.not(0), z)))def Date.sub_ov(+z: U32, n: U32, ok: Bool) -> Result<&2, &2, Date.Error, Date>:  match ok:    case False{}:      Fail{OutOfRange{}}    case True{}:      Date.from_days(U32.sub(z, n))def Date.sub_days(+date: Date, +n: U32) -> Result<&2, &2, Date.Error, Date>:  +z = Date.to_days(date)  Date.sub_ov(z, n, U32.is_ge(z, n))def Weekday.to_u32(w: Weekday) -> U32:  match w:    case Mon{}:      0    case Tue{}:      1    case Wed{}:      2    case Thu{}:      3    case Fri{}:      4    case Sat{}:      5    case Sun{}:      6def Weekday.fwd.gap(+cur: U32, +tgt: U32, gt: Bool) -> U32:  match gt:    case True{}:      U32.sub(tgt, cur)    case False{}:      U32.sub(U32.add(tgt, 7), cur)def Weekday.fwd.eq(+cur: U32, +tgt: U32, eq: Bool) -> U32:  match eq:    case True{}:      7    case False{}:      Weekday.fwd.gap(cur, tgt, U32.is_gt(tgt, cur))def Weekday.fwd(+cur: U32, +tgt: U32) -> U32:  Weekday.fwd.eq(cur, tgt, U32.is_eq(tgt, cur))def Date.next_weekday(  +d: Date, w: Weekday) -> Result<&2, &2, Date.Error, Date>:  Date.add_days(    d, Weekday.fwd(Weekday.to_u32(Date.weekday(d)), Weekday.to_u32(w))  )def Date.previous_weekday(  +d: Date, w: Weekday) -> Result<&2, &2, Date.Error, Date>:  Date.sub_days(    d, Weekday.fwd(Weekday.to_u32(w), Weekday.to_u32(Date.weekday(d)))  )def Date.next_or_same.go(  +d: Date, w: Weekday, eq: Bool) -> Result<&2, &2, Date.Error, Date>:  match eq:    case True{}:      Done{d}    case False{}:      Date.next_weekday(d, w)def Date.next_or_same_weekday(  +d: Date, +w: Weekday) -> Result<&2, &2, Date.Error, Date>:  Date.next_or_same.go(    d, w, U32.is_eq(Weekday.to_u32(Date.weekday(d)), Weekday.to_u32(w))  )def Date.previous_or_same.go(  +d: Date, w: Weekday, eq: Bool) -> Result<&2, &2, Date.Error, Date>:  match eq:    case True{}:      Done{d}    case False{}:      Date.previous_weekday(d, w)def Date.previous_or_same_weekday(  +d: Date, +w: Weekday) -> Result<&2, &2, Date.Error, Date>:  Date.previous_or_same.go(    d, w, U32.is_eq(Weekday.to_u32(Date.weekday(d)), Weekday.to_u32(w))  )def Date.until_days.go(  +zs: U32, +ze: U32, lt: Bool) -> Result<&2, &2, Date.Error, U32>:  match lt:    case True{}:      Fail{OutOfRange{}}    case False{}:      Done{U32.sub(ze, zs)}def Date.until_days(  start: Date, end: Date) -> Result<&2, &2, Date.Error, U32>:  +zs = Date.to_days(start)  +ze = Date.to_days(end)  Date.until_days.go(zs, ze, U32.is_lt(ze, zs))