Work calendar
The work calendar defines once per account which days are off: the public holidays of the German state, regional holidays and days off the company grants. Processes count working days with it, for example in a vacation request, the planning board shows the days off, and a form can show while it is being filled in how many working days a period costs. Holidays are not maintained by hand but computed from rules – for every year, without updates.
What is the work calendar used for?
- Vacation request: The days of a request are counted without public holidays, with half days at the start or end and with the person's working weekdays (for example Monday to Thursday in a four-day week).
- Sick note, training, business trip: The same count for every absence measured in working days.
- Deadlines and delivery times: Check whether a date is a working day, or count the working days between two dates.
- Planning board: Public holidays and half days off appear as unavailable time without a state being maintained in the widget.
- Forms: A display field shows "5 working days" while filling in, and optionally "6 remain available afterwards".
- AI assistants: A connected assistant counts working days and names public holidays and bridge days, for example when asked "How many vacation days does 22 Dec to 9 Jan cost in a four-day week?".
Setting it up
The work calendar is set up under Administration → System → Work calendar, by administrators. The page has five sections:
- State – determines the public holidays. The place of work counts, not the place of residence of the employees.
- Regional holidays – holidays that apply only in parts of the state, as switches. Only the switches of the chosen state are shown, for example Assumption of Mary and the Augsburg Peace Festival in Bavaria or Corpus Christi in Saxony and Thuringia.
- Christmas Eve and New Year's Eve – each as "Working day", "Half day off" or "Whole day off". A granted day does not cost vacation.
- Further days off granted by the company – for example a bridge day or a company party in the afternoon, with date, "Every year" and whole or half day.
- Preview – all days off of the current and the next year with their source (law, regional, company). The preview follows every change, also before saving.
Changes are stored with Save. If two people change the calendar at the same time, the second change is rejected and the current version is loaded.
Without setup
As long as no work calendar is saved, only the nationwide public holidays apply: New Year's Day, Good Friday, Easter Monday, Labour Day, Ascension Day, Whit Monday, German Unity Day, Christmas Day and Boxing Day. Processes run anyway; the page shows the note "not set up yet".
Company vacation does not belong in the work calendar
Company vacation costs vacation and is created as an absence per employee. The work calendar holds only days that do not cost vacation.
What counts as a working day?
For every day of a period:
- The day counts 1 when it is one of the person's working weekdays (default: Monday to Friday).
- A whole public holiday or a whole company day off counts 0, a half day off 0.5.
- When the first or last day is marked as a half day, it counts at most 0.5.
The result is always a multiple of 0.5. A public holiday on a Saturday does not count for a person working Monday to Friday – it was not a working day anyway.
Public holidays
| Holiday | Date | States |
|---|---|---|
| New Year's Day | 1 Jan | all |
| Epiphany | 6 Jan | BW, BY, ST |
| International Women's Day | 8 Mar | BE (from 2019), MV (from 2023) |
| Good Friday, Easter Monday | movable | all |
| Labour Day | 1 May | all |
| Ascension Day, Whit Monday | movable | all |
| Corpus Christi | movable | BW, BY, HE, NW, RP, SL |
| Assumption of Mary | 15 Aug | SL; in BY per municipality (switch) |
| World Children's Day | 20 Sep | TH (from 2019) |
| German Unity Day | 3 Oct | all |
| Reformation Day | 31 Oct | BB, MV, SN, ST, TH; HB, HH, NI, SH (from 2018) |
| All Saints' Day | 1 Nov | BW, BY, NW, RP, SL |
| Day of Repentance and Prayer | Wednesday before 23 Nov | SN |
| Christmas Day, Boxing Day | 25/26 Dec | all |
One-off holidays such as 31 October 2017 (500 years of the Reformation) or 8 May 2020 and 2025 in Berlin are included, so past periods are counted correctly as well.
Counting working days in a process
Four functions are available in processes, in JSONata expressions as well as in texts with $(…) placeholders (see Template functions). They always use the account's work calendar.
| Function | Result | Example |
|---|---|---|
date_workdays(from, to, workdays?, halfStart?, halfEnd?) |
working days as a number, e.g. 4.5 |
$fn('date_workdays', request.from, request.to, employee.workdays, request.first_day_half, request.last_day_half) |
date_workdaysByYear(from, to, workdays?, halfStart?, halfEnd?) |
working days per year, e.g. { "2026": 4, "2027": 4 } |
split a request over New Year into two absences |
date_isWorkday(date, workdays?) |
true or false |
$fn('date_isWorkday', $now()) |
date_freeDays(from, to) |
list of the days off [{ "date", "name", "fraction" }] |
name the holidays in an e-mail |
Arguments:
from,to: dates asYYYY-MM-DD, both days included. A timestamp is cut to its date. The period may span at most three years.workdays: the person's weekdays as a list or text, for example[1,2,3,4,5],"1,3,5"or"Mon,Tue,Wed"; 1 = Monday … 6 = Saturday, 0 or 7 = Sunday. Without it, Monday to Friday applies.halfStart,halfEnd:truewhen the first or last day counts half.
An example input mapping of a step that stores the request:
{
"employee": request.employee.id,
"from": request.from,
"to": request.to,
"days": $fn('date_workdays', request.from, request.to, request.employee.workdays, request.first_day_half, request.last_day_half)
}
Invalid input stops the step with a readable message, for example "Das Ende liegt vor dem Beginn. Bitte ‚Bis‘ anpassen." (the end is before the start, please adjust "To"). The order of the dates is therefore best ensured in the form already (see Binding "To" to "From") or checked with a condition.
Store the counted days
The days are counted with the request and stored on the record. Reports and remaining vacation then only use the stored days. If a person's weekdays change later, old requests stay as they are.
Planning board
In the planning board the setting Public holidays in the "Rows" tab defines where holidays come from:
- Work calendar of the account – public holidays, regional holidays and company days off from the work calendar; half days as half availability. Default for new boards.
- State of the board (built-in rules) – only the public holidays of the state chosen in the widget. Boards created before the work calendar existed keep this setting.
- No holidays
Rows with their own state (column region in the rows query) get the public holidays of that state when it differs from the account's. When a period is dragged, the board counts working days like the process does; a half day off counts 0.5.
Showing it in a form: "costs 5 days"
The field type workday-count shows in a form the working days between two date fields while the form is being filled in – with the work calendar, the person's weekdays and half days. The field is not tied to vacation; it fits sick notes, trainings or rental periods just as well. The settings of the field are described under Forms → Working days.
Property (props) |
Meaning |
|---|---|
fromKey, toKey |
keys of the two date fields (required), also nested like request.to |
halfStartKey, halfEndKey |
yes/no fields: the first or last day counts half |
workdaysKey or workdays |
field with the person's weekdays (list or text) or a fixed list; without it Monday to Friday |
remainingKey |
field with the available days, for example remaining vacation: shows "6 remain available afterwards", a note when exceeded |
remainingByYearKey |
field with the available days per year, for example {"2026": 8, "2027": 28}. A request over the turn of the year takes each year's days from its own year: "Afterwards 4 for 2026, 26 for 2027 remain available"; if a year is not enough, a note for that year appears. When the field has a value, it applies instead of remainingKey |
showFreeDays |
list the days off inside the period (default on) |
label, unit, unitOne, description |
texts of the field |
With a key the number goes into the form result as a proposal. The process still counts for itself with date_workdays when it saves – the browser is not trusted.
[
{ "key": "from", "type": "dateInput", "defaultValue": "today", "props": { "label": "From", "required": true } },
{ "key": "to", "type": "dateInput", "defaultValue": "today", "props": { "label": "To", "required": true, "minKey": "from", "followMin": true } },
{ "key": "first_day_half", "type": "toggle", "props": { "label": "First day half" } },
{ "key": "last_day_half", "type": "toggle", "props": { "label": "Last day half" } },
{
"key": "days",
"type": "workday-count",
"props": {
"label": "Vacation days",
"fromKey": "from",
"toKey": "to",
"halfStartKey": "first_day_half",
"halfEndKey": "last_day_half",
"workdaysKey": "employee.workdays",
"remainingKey": "remaining_days"
}
}
]
employee.workdays and remaining_days are provided by the process as input of the form. Without them the field counts Monday to Friday and leaves out "remain available". If requests over the turn of the year are allowed, provide the remaining vacation per year instead of one number and use remainingByYearKey. In an external task without login the field stays empty; the process counts anyway.
Binding "To" to "From"
If "From" and "To" both start on today and the user moves "From" to a later day, "To" would first lie before it. The workday-count field would then report that the end is before the start, although the user is simply not done yet. The date fields (dateInput, and dateTimeInput as well) have their own properties for this:
Property (props) |
Meaning |
|---|---|
minKey, maxKey |
Key of another date field on the same level (in a repeat: in the same entry). Its value is the earliest or latest allowed day. |
min, max |
Fixed limit: YYYY-MM-DD, today, today+N or today-N; for date and time also now |
followMin |
true: if the field from minKey moves past this one, this field takes its value. An empty field stays empty; if "From" is set earlier, "To" stays where it is. |
In the calendar, days outside the limits are greyed out. If a date outside is typed in, the field shows for example "Must not be before ‘From’." or "On Nov 5, 2026 at the earliest.", and the form cannot be submitted. The properties apply to own forms (Formly JSON), for example an own start form; they are not set in the Data Designer.
Frequently asked questions
Do changes to the work calendar apply retroactively? No. Days stored on absences stay as they were counted. New counts use the changed settings immediately.
Are there several locations in different states?
One work calendar applies per account. On the planning board, single rows can carry another state through the region column; in a process the person's state cannot be given individually yet.
Where do the holidays come from? From rules in Pantarey: fixed dates, the Easter formula for movable holidays and the assignment to the states, including the years from which a holiday applies. Nothing has to be added each year.