Most take-home pay calculators I've read share one shortcut: they turn every deduction into an annual rate and multiply. For Irish pay in 2026 that shortcut gives the wrong answer, because one of the three deductions changes rate partway through the year.
I hit this while building Irishtakehome, a take-home calculator for Irish salaries. This post walks through the model with one worked example: a single employee on €45,000, paid weekly, with no pension. All rates below are the 2026 rules as of 15 October 2026.
Three charges, three bases
Irish payroll takes three separate charges out of a salary, and each one is worked out on a different base.
Income tax (PAYE) is banded, then reduced by credits. A single person pays 20% on the first €44,000 of taxable pay and 40% on the rest. The personal tax credit (€2,000) and the employee tax credit (€2,000) come off the tax itself, not off the pay.
20% of €44,000 = €8,800
40% of €1,000 = €400
less credits = −€4,000
PAYE = €5,200
USC (Universal Social Charge) has its own bands:
| Slice of income | Rate |
|---|---|
| First €12,012 | 0.5% |
| Next €16,688 (up to €28,700) | 2% |
| Next €41,344 (up to €70,044) | 3% |
| Balance over €70,044 | 8% |
On €45,000 that's €60.06 + €333.76 + €489.00 = €882.82.
USC also has a threshold that behaves differently from a band. Income of €13,000 or less pays no USC at all, but once you go over it, USC applies to all of your income from the first euro. If you write this as a marginal band, people just above €13,000 get the wrong figure.
PRSI (social insurance, Class A employee) is charged per pay period, on the whole of that period's pay. Weekly pay from €38 to €352 pays nothing. Above €352, the rate is:
- 4.2% of the whole week's pay for pay dates up to 30 September 2026
- 4.35% of the whole week's pay for pay dates from 1 October 2026
Between €352.01 and €424 a week a credit of up to €12 reduces the charge. I've left that band out of the code below to keep it short; our example pays €865.38 a week, well above it.
Why an annual rate is wrong here
If you treat PRSI as one rate for the year you get one of these:
flat 4.2% on €45,000 = €1,890.00 (too low)
flat 4.35% on €45,000 = €1,957.50 (too high)
The real figure depends on how many pay dates fall on each side of 1 October. PRSI is worked out on each pay period, so the rate that applies is the one in force on the pay date. Here is the model I ended up with:
from datetime import date, timedelta
from decimal import Decimal, ROUND_HALF_UP
CENT = Decimal("0.01")
RATE_CHANGE = date(2026, 10, 1)
def weekly_prsi(weekly_pay: Decimal, pay_date: date) -> Decimal:
if weekly_pay <= Decimal("352"):
return Decimal("0") # nil band (the credit band from €352.01 to €424 is left out here)
rate = Decimal("0.042") if pay_date < RATE_CHANGE else Decimal("0.0435")
return (weekly_pay * rate).quantize(CENT, ROUND_HALF_UP)
salary = Decimal("45000")
weekly = salary / 52
first_pay = date(2026, 1, 2) # 52 Friday pay dates in 2026
pays = [first_pay + timedelta(weeks=i) for i in range(52)]
total = sum(weekly_prsi(weekly, d) for d in pays)
before = sum(1 for d in pays if d < RATE_CHANGE)
print(f"pays at 4.2%: {before}, at 4.35%: {52 - before}")
print(f"PRSI for the year: €{total}")
Output:
pays at 4.2%: 39, at 4.35%: 13
PRSI for the year: €1906.97
Thirty-nine Friday pays fall before 1 October and thirteen after. Each week's charge is rounded to the cent on its own, as it is on a payslip, so the year comes to €1,906.97, between the two flat figures. The last thirteen payslips of the year each take a little more PRSI than the first thirty-nine, and a model with one annual rate can't show that.
Putting it together
Salary €45,000.00
PAYE −€5,200.00
USC −€882.82
PRSI −€1,906.97
Take-home pay €37,010.21 (82% kept)
The pension trap
The other place a single rate lets you down is pension contributions. A contribution taken from pay by an employer's approved scheme lowers the pay PAYE is worked out on. It doesn't lower the pay USC and PRSI are charged on. So if your model subtracts the pension from gross pay once and then runs all three charges on the result, it overstates the saving.
In code, that means keeping two bases instead of one:
paye_base = gross - pension_contribution
usc_base = gross
prsi_base = gross
Tax relief on the pension also has an age-related cap (15% to 40% of earnings, with earnings counted up to €115,000), so the PAYE base can't drop without limit either.
What I'd tell anyone writing payroll code
- Store rates with an effective date, and look them up by pay date.
- Round per pay period, the way a payslip does, then add up.
- Keep a separate base for each charge. They stop matching as soon as a pension contribution comes in.
- Treat cliff thresholds like USC's €13,000 as their own rule, not as a band.
If you want to check your own numbers against these rules, the worked example above is the calculator's default case, and every figure in this post comes from it. Has anyone here modelled a mid-year rate change in another country's payroll? I'd like to hear how you handled the pay-date rule.
Top comments (0)