period.bend
bend-time-lib@0.4.0.1 · 171 lines · 22 definitions
1import Base
2import bend-time-lib@0.4.0.1/date.bend as D
3
4type Period.Error is Data:
5 OutOfRange{}
6
7type Period is Data:
8 Period{years: U32, months: U32, days: U32}
9
10def Period.from.y(
11 +years: U32, +extra: U32, +months: U32, +days: U32, ok: Bool
12) -> Result<&2, &2, Period.Error, Period>:
13 match ok:
14 case False{}:
15 Fail{OutOfRange{}}
16 case True{}:
17 Done{Period{U32.add(years, extra), months, days}}
18
19def Period.from(
20 +years: U32, +months: U32, +days: U32
21) -> Result<&2, &2, Period.Error, Period>:
22 +extra = U32.div(months, 12)
23 Period.from.y(
24 years, extra, U32.mod(months, 12), days,
25 U32.is_le(extra, U32.sub(U32.not(0), years))
26 )
27
28def Period.add_to.days(
29 r: Result<&2, &2, D.Date.Error, D.Date>, pd: U32
30) -> Result<&2, &2, D.Date.Error, D.Date>:
31 match r:
32 case Fail{e}:
33 Fail{e}
34 case Done{date}:
35 D.Date.add_days(date, pd)
36
37def Period.add_to.from(
38 +y: U32, +m: U32, +d: U32, +pd: U32
39) -> Result<&2, &2, D.Date.Error, D.Date>:
40 Period.add_to.days(D.Date.from(y, m, d), pd)
41
42def Period.add_to.day(
43 +y: U32, +m: U32, +d: U32, +pd: U32, +dim: U32, le: Bool
44) -> Result<&2, &2, D.Date.Error, D.Date>:
45 match le:
46 case True{}:
47 Period.add_to.from(y, m, d, pd)
48 case False{}:
49 Period.add_to.from(y, m, dim, pd)
50
51def Period.add_to.dim(
52 +y: U32, +m: U32, +d: U32, +pd: U32, dimr: Maybe<&2, U32>
53) -> Result<&2, &2, D.Date.Error, D.Date>:
54 match dimr:
55 case None{}:
56 Fail{D.OutOfRange{}}
57 case Some{+dim}:
58 Period.add_to.day(y, m, d, pd, dim, U32.is_le(d, dim))
59
60def Period.add_to.y3(
61 +y: U32, +m: U32, +d: U32, +pd: U32, ok: Bool
62) -> Result<&2, &2, D.Date.Error, D.Date>:
63 match ok:
64 case False{}:
65 Fail{D.OutOfRange{}}
66 case True{}:
67 Period.add_to.dim(y, m, d, pd, D.Date.dim(m, D.Date.leap(y)))
68
69def Period.add_to.y2(
70 +y: U32, +m: U32, +d: U32, +pd: U32
71) -> Result<&2, &2, D.Date.Error, D.Date>:
72 Period.add_to.y3(y, m, d, pd, Bool.and(U32.is_ge(y, 1), U32.is_le(y, 9999)))
73
74def Period.add_to.mc(
75 +y: U32, +m: U32, +d: U32, +pd: U32, ge: Bool
76) -> Result<&2, &2, D.Date.Error, D.Date>:
77 match ge:
78 case False{}:
79 Period.add_to.y2(y, m, d, pd)
80 case True{}:
81 Period.add_to.y2(U32.add(y, 1), U32.sub(m, 12), d, pd)
82
83def Period.add_to.ya(
84 +dy: U32, +py: U32, +dm: U32, +pm: U32, +dd: U32, +pd: U32, ok: Bool
85) -> Result<&2, &2, D.Date.Error, D.Date>:
86 match ok:
87 case False{}:
88 Fail{D.OutOfRange{}}
89 case True{}:
90 +y = U32.add(dy, py)
91 +m = U32.add(dm, pm)
92 Period.add_to.mc(y, m, dd, pd, U32.is_gt(m, 12))
93
94def Period.add_to.go(
95 date: D.Date, p: Period
96) -> Result<&2, &2, D.Date.Error, D.Date>:
97 match date p:
98 case D.Date{+dy, +dm, +dd} Period{+py, +pm, +pd}:
99 Period.add_to.ya(
100 dy, py, dm, pm, dd, pd, U32.is_le(py, U32.sub(U32.not(0), dy))
101 )
102
103def Period.add_to(
104 p: Period, date: D.Date
105) -> Result<&2, &2, D.Date.Error, D.Date>:
106 Period.add_to.go(date, p)
107
108def Period.emonth(+y: U32, +m: U32) -> U32:
109 U32.add(U32.mul(y, 12), m)
110
111def Period.between.ms.from(
112 +end: D.Date, +tm: U32, r: Result<&2, &2, D.Date.Error, D.Date>
113) -> Result<&2, &2, Period.Error, Period>:
114 match r:
115 case Fail{_}:
116 Fail{OutOfRange{}}
117 case Done{start2}:
118 Period.from(
119 U32.div(tm, 12),
120 U32.mod(tm, 12),
121 U32.sub(D.Date.to_days(end), D.Date.to_days(start2))
122 )
123
124def Period.between.ms.add(
125 +start: D.Date, +end: D.Date, +tm: U32,
126 rp: Result<&2, &2, Period.Error, Period>
127) -> Result<&2, &2, Period.Error, Period>:
128 match rp:
129 case Fail{_}:
130 Fail{OutOfRange{}}
131 case Done{pM}:
132 Period.between.ms.from(end, tm, Period.add_to(pM, start))
133
134def Period.between.ms(
135 +start: D.Date, +end: D.Date, +tm: U32
136) -> Result<&2, &2, Period.Error, Period>:
137 Period.between.ms.add(start, end, tm, Period.from(0, tm, 0))
138
139def Period.between.day(
140 start: D.Date, end: D.Date, sm: U32, em: U32, borrow: Bool
141) -> Result<&2, &2, Period.Error, Period>:
142 match borrow:
143 case True{}:
144 Period.between.ms(start, end, U32.sub(U32.sub(em, sm), 1))
145 case False{}:
146 Period.between.ms(start, end, U32.sub(em, sm))
147
148def Period.between.go(
149 +start: D.Date, +end: D.Date
150) -> Result<&2, &2, Period.Error, Period>:
151 match start end:
152 case D.Date{+sy, +sm, +sd} D.Date{+ey, +em, +ed}:
153 Period.between.day(
154 start, end,
155 Period.emonth(sy, sm), Period.emonth(ey, em),
156 U32.is_lt(ed, sd)
157 )
158
159def Period.between.ord(
160 start: D.Date, end: D.Date, lt: Bool
161) -> Result<&2, &2, Period.Error, Period>:
162 match lt:
163 case True{}:
164 Fail{OutOfRange{}}
165 case False{}:
166 Period.between.go(start, end)
167
168def Period.between(
169 +start: D.Date, +end: D.Date
170) -> Result<&2, &2, Period.Error, Period>:
171 Period.between.ord(start, end, D.Date.is_lt(end, start))