LanguageValues and typesStandard typesMoney and banking
ExchangeRate
On this page
A rate between two currencies at a moment in time.
Use it to record the rate you were given and to convert: money.convert applies one. Jadpo doesn't fetch rates, so your app gets them from a provider.
Shape
Example
ExchangeRate { from: Currency.gbp to: Currency.eur rate: 1.17 at: "2026-10-18T09:00:00Z" }text.parse(raw, as: ExchangeRate) reads one from text that comes from outside. Text that isn't one at all fails malformed, such as GBP/EUR 1.17, GBP-EUR 1.17 2026-10-18T09:00:00Z or GBP/XYZ 1.17 2026-10-18T09:00:00Z.
Good to know
- It holds when the rate applied, so keep it with what you converted to show later how a figure was reached.
==tells you whether two are the same.<andlist.sort_bydon't take it, so sort by one of its parts instead.
In JSON
An object of its parts, in a request, a response or json.write:
{"from":"GBP","to":"EUR","rate":"1.17","at":"2026-10-18T09:00:00Z"}{"from":"EUR","to":"JPY","rate":"162.4031","at":"2026-10-18T09:30:00Z"}
Details
Text form, storage, how it is shown, and operations
ExchangeRate is in the group Money and banking, and has been in Jadpo since 0.1.0.
Text form
text.from writes one standard text form, the same form text.parse reads back: GBP/EUR 1.17 2026-10-18T09:00:00Z and EUR/JPY 162.4031 2026-10-18T09:30:00Z.
How it is stored
It is stored in 4 columns, each named for the field, _ and its suffix. This is EUR/JPY 162.4031 2026-10-18T09:30:00Z:
| Column | Type | Holds |
|---|---|---|
<field>_from |
char(3) |
'EUR' |
<field>_to |
char(3) |
'JPY' |
<field>_rate |
numeric |
162.4031 |
<field>_at |
timestamptz(3) |
'2026-10-18 09:30:00.000000+00'::timestamptz |
How it is shown to people
text.format(value, locale:) shows it to people in their locale.
With locale: Locale.en_gb:
| Value | Shown |
|---|---|
GBP/EUR 1.17 2026-10-18T09:00:00Z |
GBP/EUR 1.17 2026-10-18T09:00:00Z |
EUR/JPY 162.4031 2026-10-18T09:30:00Z |
EUR/JPY 162.4031 2026-10-18T09:30:00Z |
Operations
money.convert(value: Money, rate: ExchangeRate) -> Money:valueinrate'stocurrency, from itsfromone: the major units timesrate.rate, rounded half to even to a minor unit, so £10.50 at aGBP/EURrate of 1.17 is €12.28. It fails withcurrency_mismatchwhenvalueisn't inrate.from, unless that is known: an inverted rate is then a compile error. The rate is one the app holds; nothing here fetches one.
It also takes text.parse, text.from, text.format, json.read, json.write and ==. How every standard type behaves says how they work.
Markdown for agents: /docs/types/type-exchange-rate.md.Built from Jadpo main at aee2e8f.