Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Windows Tipps & SecurityNighthawk M7 Pro im Test: Flexibler, aber teurer 5G-Router(21.09.2026 um 10:30 Uhr)
Sichere ProgrammierungNeue Gmail-Funktion: So sparst du jetzt Zeit bei Einmalcodes(21.09.2026 um 10:00 Uhr)
Sichere ProgrammierungYour GIF exporter is fine — the container is the problem(21.09.2026 um 10:01 Uhr)
Sichere ProgrammierungCSS, Motion, or GSAP? I Choose by Who Owns the Animation(21.09.2026 um 10:12 Uhr)
Windows Tipps & SecurityNighthawk M7 Pro im Test: Flexibler, aber teurer 5G-Router(21.09.2026 um 10:30 Uhr)
Sichere ProgrammierungNeue Gmail-Funktion: So sparst du jetzt Zeit bei Einmalcodes(21.09.2026 um 10:00 Uhr)
Sichere ProgrammierungYour GIF exporter is fine — the container is the problem(21.09.2026 um 10:01 Uhr)
Sichere ProgrammierungCSS, Motion, or GSAP? I Choose by Who Owns the Animation(21.09.2026 um 10:12 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Your budgeting app is lying to you about last month

I build a multi-currency personal-finance app. This is one of the first bugs I had to design my way out of — and it's one almost every multi-currency app I've tried still has. The symptom You spent 200 zł on groceries in March. Y…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

I build a multi-currency personal-finance app. This is one of the

first bugs I had to design my way out of — and it's one almost every

multi-currency app I've tried still has.





The symptom



You spent 200 zł on groceries in March. Your base currency is euros.

In March the app showed that as, say, €46. You open the app in July and

that same March transaction now reads €43 — even though nothing about

March changed. Multiply that across every foreign transaction and your

"total spent in March" quietly drifts every single day.



That's not a rounding quirk. It means your financial history is being

rewritten with today's exchange rate, and you can't trust any

number older than right now.





Why it happens



The naive multi-currency data model looks reasonable:




transaction {
amount: 200
currency: "PLN"
date: "2026-03-14"
}






Then, to show a total in the user's base currency, you convert on read:




const eur = amount * liveRate(currency, "EUR");






liveRate returns today's rate. So the March transaction is re-priced

with the July rate every time it's rendered. Balances update live —

which is correct for what you hold right now — but the same logic

leaks onto historical transactions, where it's just wrong. A cost

you actually incurred at March's rate should read at March's rate

forever.





The principle




Convert live for balances. Snapshot for history.




A transaction is an event that happened at a moment in time. The

exchange rate that applied is a fact about that moment, not a live

value. So capture it once, at ingest, and never recompute it:




transaction {
amount: 200
currency: "PLN"
date: "2026-03-14"
rate_to_base: 0.2312 // EUR per PLN on the value date, frozen
amount_base: 46.24 // optional: precomputed, for fast sums
}






Now historical totals are a plain SUM(amount_base) — deterministic,

and March stays €46.24 in July, next year, forever. Only current

account balances get the live rate, because those really are

"what is this worth right now."






The details that bite



Which date's rate? Use the transaction's value date (when the

money actually moved), not the booking/import date. Banks can book days

later; pricing at import time reintroduces drift.



Rates aren't published every day. The ECB (I use their Frankfurter

feed) publishes on TARGET business days — no weekends, no holidays. A

Saturday transaction has no same-day rate. Carry forward the last

published rate rather than skipping or interpolating; that's what the

banks do too.



Some currencies aren't in the feed. The ECB doesn't publish UAH,

for example. You need a secondary source for the long tail, normalized

into the same base so your snapshot is consistent regardless of which

feed a given currency came from.



Store the rate, not just the converted amount. If you only store

amount_base, you can never let the user change their base currency

without lying again. Keep the original amount + currency + date,

and the snapshotted rate. To switch base currency you re-derive from

the original at each transaction's historical rate — which means you

also need historical rates on hand, not just today's. (Storing the

rate against a single pivot currency like EUR and deriving cross-rates

keeps this cheap.)



Idempotency. Banks re-send transactions. Snapshot the rate keyed to

the transaction's identity + value date so a re-sync never re-prices an

existing row.






The takeaway



If you're building anything that sums money across currencies over

time — budgeting, accounting, portfolio, expenses — decide explicitly,

per number, whether it's a live value or a historical one.

Balances are live. Everything that already happened is history, and

history needs its rate frozen at the moment it occurred. Get this wrong

and every chart you draw is quietly fiction.






I'm building EveryPenny, a calm

multi-currency money tracker for people whose money lives across more

than one country — it connects EEA banks and Monobank in Ukraine and

shows one honest total. It's what pushed me to get this right. Happy to

go deeper on the rate-sourcing side in the comments.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Your budgeting app is lying to you about last month

Thematisch verwandte Begriffe: Your, budgeting, lying, about · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-94030 | A security vulnerability has been detected in SerenityOS up to 3d83e4509…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick