Spanish tax calendar

When each Spanish tax form falls due, computed rather than copied from a table.

Open-source libraries · Python · Code published

The problem

A filing deadline looks like a fact and is a calculation. The day depends on the form, it shifts if it lands on a Saturday, Sunday or public holiday, and it moves five days earlier when payment is direct-debited. Any hand-written calendar is correct the year it is written and silently wrong the next.

What it does

  • Computes the deadline for the quarterly, annual and campaign forms of the Spanish tax agency.
  • Shifts the due date when it falls on a non-working day, per article 30.5 of Act 39/2015.
  • Brings the deadline five days forward when the filing is paid by direct debit.
  • Locates Good Friday with the Meeus/Jones/Butcher algorithm instead of listing years by hand.

What was decided while building it

Easter is computed, not listed
Good Friday is the only movable national holiday, and the temptation is to write ten years into a table. That table expires without warning: year eleven returns a wrong date and nothing looks odd. With the Meeus/Jones/Butcher algorithm, year eleven comes out as well as the first.
The shift comes from the law that states it
A deadline landing on a non-working day moving to the next working day is not a custom: it is article 30.5 of Act 39/2015, cited in the code right beside the line that applies it. A rule without its source next to it is a rule nobody can review without researching it again from scratch.
Direct debit shortens the deadline, it does not extend it
Direct-debiting the payment moves the real filing date five days earlier, and it is the most expensive mistake of the set because it runs against intuition: anyone assuming direct debit buys time files late. It is an explicit parameter, not a special case buried somewhere.

How far it goes

  • It fills in no form, computes no amount and files nothing with the tax agency.
  • It is not tax advice: it says when a form falls due, not whether you are required to file it.
  • Coverage is the list of forms declared in the repository. A form outside that list has no date.
  • Form 100 only returns a date for the campaign years verified in the repository.
  • 0 dependencies
  • MIT licence
  • 3.9+ Python

Built with

  • Python
  • datetime

Backs this service

Bespoke software and application development

Read the code