Fully typed TypeScript utilities for Polish finance: NBP exchange rates, public holidays / working days, VAT calculations, and PLN formatting.
- Strict TypeScript, ships dual ESM + CJS builds with
.d.ts - Zero runtime dependencies — the NBP client uses the global
fetch(Node.js 20+), everything else is pure logic - Tree-shakeable; import the whole package or a single subpath
- Moving Polish holidays computed from Easter Sunday (Meeus/Jones/Butcher algorithm), not a hardcoded table
npm install @m8t-jacob/pln-utilsimport { addVat, formatPln, getExchangeRate, isWorkingDay } from '@m8t-jacob/pln-utils';
await getExchangeRate('USD'); // { code: 'USD', rate: 4.05, date: '2025-01-15', table: 'A' }
addVat(100, 23); // 123
formatPln(1234.56); // '1 234,56 zł'
isWorkingDay('2025-05-01'); // false (Święto Pracy)You can also import from a subpath if you only need one module, which keeps bundlers from pulling in the others:
import { getExchangeRate } from '@m8t-jacob/pln-utils/nbp';
import { getHolidays, isWorkingDay } from '@m8t-jacob/pln-utils/holidays';
import { addVat, removeVat } from '@m8t-jacob/pln-utils/vat';
import { formatPln, parsePln } from '@m8t-jacob/pln-utils/format';| Function | Description |
|---|---|
getExchangeRate(code, options?): Promise<ExchangeRate> |
Table A mid rate for one currency, for today or options.date |
getExchangeRates(options?): Promise<ExchangeRate[]> |
Full table (A, B, or C) for today or options.date |
getGoldPrice(options?): Promise<{ price: number; date: string }> |
NBP gold price (PLN per gram) |
convert(amount, from, to, options?): Promise<number> |
Converts an amount between two currencies via PLN (table A mid rates) |
NbpError |
Thrown for invalid input, network failures, or non-OK API responses |
All NBP functions throw NbpError for an invalid 3-letter currency code, a
malformed date (must be YYYY-MM-DD), a 404 (e.g. no table published for
that date), or a network failure. None of them are tested against the live
API — the test suite mocks fetch so CI runs deterministically offline.
| Function | Description |
|---|---|
getHolidays(year): Holiday[] |
All Polish statutory public holidays for a year, sorted chronologically |
isHoliday(date): boolean |
Whether a Date or YYYY-MM-DD string is a public holiday |
isWorkingDay(date): boolean |
true unless the date is a weekend or a public holiday |
addWorkingDays(date, n): Date |
Adds (or subtracts, for negative n) n working days |
workingDaysBetween(start, end): number |
Counts working days strictly between two dates (order-independent) |
getEaster(year): Date |
Easter Sunday for a year (Meeus/Jones/Butcher algorithm) |
Moving holidays (Easter Sunday and Monday, Pentecost +49 days, Corpus
Christi +60 days) are derived from getEaster, not hardcoded per year.
| Function | Description |
|---|---|
VAT_RATES |
{ STANDARD: 23, REDUCED_8: 8, REDUCED_5: 5, ZERO: 0 } |
addVat(net, rate): number |
Adds VAT to a net amount, returning the gross amount |
removeVat(gross, rate): number |
Removes VAT from a gross amount, returning the net amount |
vatAmount(net, rate): number |
The VAT amount itself |
netToGross(net, rate): number |
Alias for addVat |
grossToNet(gross, rate): number |
Alias for removeVat |
roundToGrosze(value): number |
Float-safe rounding to two decimal places (grosze) |
All amounts are rounded to grosze (two decimal places) using a float-safe
rounding helper, avoiding classic IEEE-754 issues like 1.005 * 100 not
rounding as expected.
| Function | Description |
|---|---|
formatPln(amount, options?): string |
Formats a number as 1 234,56 zł (Polish locale, Intl.NumberFormat) |
parsePln(str): number |
Parses a formatted PLN string back into a number |
formatPln accepts { decimals?: number; symbol?: boolean }. Note that
the thousands separator is a non-breaking space (U+00A0), matching
Intl.NumberFormat('pl-PL') output — parsePln accepts both regular and
non-breaking spaces.
@m8t-jacob/pln-utils to biblioteka narzędzi finansowych dla Polski:
klient kursów walut NBP, polskie dni ustawowo wolne od pracy i dni robocze,
kalkulacje VAT oraz formatowanie kwot w PLN. Moduł nbp korzysta z
globalnego fetch (Node.js 20+) i wymaga dostępu do sieci; pozostałe
moduły (holidays, vat, format) to czysta logika bez zależności i bez
operacji I/O. Święta ruchome (Wielkanoc, Zielone Świątki, Boże Ciało) są
wyliczane algorytmem Gaussa/Meeusa, a nie zapisane na sztywno dla każdego
roku.
Contributions are welcome! See CONTRIBUTING.md for the
development workflow and GOOD_FIRST_ISSUES.md for
ideas if you're looking for a place to start. This project follows the
Contributor Covenant.
MIT © 2026 Jakub Jagiełło