`num`, `math` and `time`
Three small namespaces: num for range tests and numeric bridging, math for arithmetic, time
for dates.
num.Between(val, min, max) → bool
Section titled “num.Between(val, min, max) → bool”Whether val is between min and max, inclusive. Whole numbers.
| Parameter | Type | Meaning |
|---|---|---|
val | int64 | The value to test |
min | int64 | Lower bound, inclusive |
max | int64 | Upper bound, inclusive |
rule TermWithinRange "loan term between 12 and 360 months" { when !num.Between(to.Int(bbox.Doc().Right("Loan Term")), 12, 360) then findings.Error("TermWithinRange", "underwriting", "Term outside the permitted 12–360 months");}num.BetweenF(val, min, max) → bool
Section titled “num.BetweenF(val, min, max) → bool”The same for floats — and the one to use for money, rates and ratios.
| Parameter | Type | Meaning |
|---|---|---|
val | float64 | The value to test |
min | float64 | Lower bound, inclusive |
max | float64 | Upper bound, inclusive |
rule RateWithinBand "rate must sit between 2% and 12%" { when !num.BetweenF(to.Num(bbox.Doc().Right("Interest Rate").Percent()), 2.0, 12.0) then findings.Error("RateWithinBand", "compliance", "Rate outside the 2–12% band");}num.ToInt64(v) → int64 · num.ToFloat64(v) → float64
Section titled “num.ToInt64(v) → int64 · num.ToFloat64(v) → float64”Bridge any numeric value into the type the language dispatches on.
| Parameter | Type | Meaning |
|---|---|---|
v | any | The value to convert |
For values that came from a document, prefer to.Int and
to.Num — they read currency symbols, separators and
accounting parentheses, which these do not.
Every function here takes and returns floats.
math.Abs(x) → float64
Section titled “math.Abs(x) → float64”| Parameter | Type | Meaning |
|---|---|---|
x | float64 | The value |
The tolerance idiom: compare a difference against a threshold rather than testing equality on values that were read off a page.
rule PaymentsRecomputeCorrectly "the stated total matches the sum of parts" { when math.Abs(to.Num(out.Get("statedTotal")) - to.Num(out.Get("computedTotal"))) > 0.01 then findings.Error("PaymentsRecomputeCorrectly", "consistency", strings.Sprintf("Stated total %s does not match computed %s", to.Fixed(out.Get("statedTotal"), 2), to.Fixed(out.Get("computedTotal"), 2)));}A cent of tolerance is deliberate: two figures rounded independently on the same document routinely differ in the last place, and a rule that fires on that is noise.
math.Min(a, b) → float64 · math.Max(a, b) → float64
Section titled “math.Min(a, b) → float64 · math.Max(a, b) → float64”| Parameter | Type | Meaning |
|---|---|---|
a, b | float64 | The two values |
math.Round(x, decimals) → float64
Section titled “math.Round(x, decimals) → float64”Rounds to decimals places.
| Parameter | Type | Meaning |
|---|---|---|
x | float64 | The value |
decimals | int64 | How many decimal places — a bare integer here |
Note the mixed types: x needs its decimal point, decimals must not have one.
math.Floor(x) → float64 · math.Ceil(x) → float64
Section titled “math.Floor(x) → float64 · math.Ceil(x) → float64”| Parameter | Type | Meaning |
|---|---|---|
x | float64 | The value |
math.Percent(part, whole) → float64
Section titled “math.Percent(part, whole) → float64”part as a percentage of whole.
| Parameter | Type | Meaning |
|---|---|---|
part | float64 | The portion |
whole | float64 | The total |
Returns a percentage, not a fraction: math.Percent(25.0, 100.0) is 25, not 0.25. That matches
to.Pct, which also does not scale.
rule LoanToValue "LTV above 80% requires mortgage insurance" { when math.Percent(to.Num(out.Get("loanAmount")), to.Num(out.Get("propertyValue"))) > 80.0 && !out.Bool("hasMortgageInsurance", false) then findings.Critical("LoanToValue", "underwriting", strings.Sprintf("LTV of %s%% requires mortgage insurance", to.Fixed(math.Percent(to.Num(out.Get("loanAmount")), to.Num(out.Get("propertyValue"))), 1)));}Guard the denominator where it may be zero or unread — to.IsNum on the property value first.
time.Now() → time
Section titled “time.Now() → time”The current time. Use sparingly: a rule that depends on the wall clock produces a different result on a rerun, which makes a decision hard to reproduce when someone asks why it was made. Prefer a date carried on the input.
time.ParseTime(layout, value) → time
Section titled “time.ParseTime(layout, value) → time”Parses value using layout.
| Parameter | Type | Meaning |
|---|---|---|
layout | string | The reference layout, e.g. "2006-01-02" |
value | string | The text to parse |
to.Date is usually better — it tries the profile’s layouts
in order, so it reads what documents actually contain without you naming the format.
time.FormatTime(t, layout) → string
Section titled “time.FormatTime(t, layout) → string”| Parameter | Type | Meaning |
|---|---|---|
t | time | The time |
layout | string | The output layout |
to.DateStr does the parse and the format in one call, and
returns the empty string rather than a formatted zero date on failure.
time.IsBefore(t1, t2) → bool · time.IsAfter(t1, t2) → bool
Section titled “time.IsBefore(t1, t2) → bool · time.IsAfter(t1, t2) → bool”Whether t1 is before / after t2.
| Parameter | Type | Meaning |
|---|---|---|
t1, t2 | time | The two times |
Guard both sides with to.IsDate first. An unreadable date is the zero time, and the zero time
compares as before everything — so an unguarded comparison silently passes or silently fires,
depending which side failed.
time.DaysBetween(t1, t2) → int64 · time.MonthsBetween(t1, t2) → int64 · time.YearsBetween(t1, t2) → int64
Section titled “time.DaysBetween(t1, t2) → int64 · time.MonthsBetween(t1, t2) → int64 · time.YearsBetween(t1, t2) → int64”The interval between two times.
| Parameter | Type | Meaning |
|---|---|---|
t1, t2 | time | The two times |
rule RescissionPeriod "closing must be at least three days after disclosure" { when to.IsDate(bbox.Doc().Right("Closing Date")) && to.IsDate(bbox.Doc().Right("Disclosure Date")) && time.DaysBetween(to.Date(bbox.Doc().Right("Disclosure Date")), to.Date(bbox.Doc().Right("Closing Date"))) < 3 then findings.Critical("RescissionPeriod", "compliance", "Fewer than three days between disclosure and closing");}time.AddDays(t, days) → time · time.AddMonths(t, months) → time
Section titled “time.AddDays(t, days) → time · time.AddMonths(t, months) → time”| Parameter | Type | Meaning |
|---|---|---|
t | time | The starting time |
days / months | int64 | How many to add — negative to subtract |
AddMonths clamps rather than overflowing: adding one month to 31 January gives the last day of
February, not 2 or 3 March.
rule RateLockExpiry "record when the rate lock runs out" { when to.IsDate(bbox.Doc().Right("Lock Date")) then out.Set("lockExpiry", time.FormatTime( time.AddDays(to.Date(bbox.Doc().Right("Lock Date")), 45), "2006-01-02"));}See also
Section titled “See also”to— conversion — reading numbers and dates out of textstrings— text — formatting a message around a figure- The rule language — operators and type dispatch