KDE PIM/KHolidays/File Format
The KHolidays file format is based on the Plan file format, but has been heavily modified to cater for alternative calendar systems and proper category support. This page documents the basics of this format and the other conventions used in standardising the content of the files. You can use this page to create a new file or to maintain an existing page.
- Always use the standard template given below
- Always complete the file metadata
- Always put Public Holidays in the separate section at the top regardless of their other categories (i.e. even if Religious)
- Always sort categories into date order
- Always include the English name of the holiday in a comment so the maintainers can understand it
- Always write dates using month name to remove any ambiguity
- Never remove old holidays or change the rule of an existing holiday to only have a new future calculation, as you still need the old holiday rule when calculating holidays for earlier years. Instead modify the year range the old and new calculations apply to. See Advanced Calculations below.
Holiday Region Files
A single holiday file defines all the holidays for an administrative region translated into a language and optionally separated into categories. This is known in KHolidays as a Holiday Region and each file/region is listed separately in the user interface where they can be enabled and disabled separately. This provides a convenient and easy way for organising large groups of holidays, for example by splitting religious holidays into a separate file for a country, or even creating a global level file for all holidays for a religion.
The file name is of the format holiday_$region_$language[_$variant], for example "holiday_es_es" for general holidays in Spain in Spanish or "holiday_es_es_catholic" for Catholic holidays in Spain in Spanish.
- The filename is always lowercase
- The filename, being unique, is used as the ID for the Holiday Region in KHolidays
- The metadata tags in the filename are separated by an underscore "_"
- Where the metadata tags require subtags these are separated by a dash "-"
- The metadata tags in the filename are used as a fallback if the internal file metadata tags are not populated, otherwise the naming standard is purely for organisational convenience.
- The region code is the ISO 3166 Alpha2 code for the administrative region that the holidays in the file apply to and is compulsory. This is usually the country level code such as "es" (Spain) or "us" (USA), but can be a level 2 region code for a state or province such as "es-ca" (Catalonia). Where the file applies at a global level, such as "Catholic Saint's Days", then the region code is "xx"
- The language code is the KDE translation code for the language that the file is in, usually the ISO 639 Language code such as "es" (Spanish) or the locale variant of the language such as "en-gb" (British English), or even with the script variant included "[email protected]" (Serbian in Latin script).
- The variant code is optional and usually omitted for the default file for an administrative region. Where a particular category has an excessive number of holidays that may not be suitable for the default file, e.g. Name Days) then these can be split into a separate file and named with the category, e.g. "holiday_gr_el_nameday" for Greek Name Days. If the file's internal Name metadata tag is not populated, then the variant code will be used by KHoliday in generating the Name. To ensure this is properly translated you must use one of the pre-defined variant tags, or add the tag and translation to the KHolidayRegion class. Currently supported variant codes are: public, civil, religious, government, financial, cultural, commemorative, historical, school, seasonal, nameday, personal, catholic, protestant, orthodox, jewish, islamic.
When creating a new holiday file please copy this template and complete all the fields within the square brackets [ ] before adding the holidays under each category heading. See below for an explanation of the categories.
All lines starting with a ":" are comments and are ignored by the parser.
:: :: Country: [Name] :: :: Language: [Name] :: :: Author: [Name <[email protected]>] :: :: Updated: [YYYY-MM-DD] :: :: Source: [Source URL 1] :: [Source URL 2] :: Metadata country "XX" language "xx" :name "[optional - defaults to country name]" description "[please add description in source language, e.g. National holiday file for $country]" :: Public Holidays :: Civil :: Religious :: Government :: Financial :: Commemorative :: Cultural :: Historical :: School :: Daylight Saving (Winter/Summer Time) :: Seasons :: Name Days
The file header section contains documentation about the file contents:
- Country: The name of the country or administrative region the file applies to.
- Language: The name of the language the file is translated into.
- Author: The name and e-mail address of the author(s) of the file, primarily used for maintenance purposes as the contents of the file may not qualify for copyright.
- Updated: Date of last significant update, i.e. when the accuracy of the Public holidays was last verified.
- Source: The URL of the source of the data, two sources are preferred of which at least one is preferred to be an official government website, and one is allowed to be Wikipedia, with preferably at least one source in English. Do not use websites that claim to hold copyright over the data.
The File Metadata section contains metadata about the file contents that will be used by the KHolidays library, so must always be completed:
- country: Compulsory. The uppercase ISO 4166 alpha 2 code for the administrative region the file contents apply to, usually the country code (e.g. "US") or a level 2 state or provincial code (e.g. "es_CA"). Level 1 country codes are automatically translated by KDE, but new level 2 state codes must have a translation added to KHolidayRegion.
- language: Compulsory. The KDE translation code for the language this file is translated into, usually the lowercase ISO 639 alpha 2 code (e.g. "es"), but also the mixed-case locale variant code as well (e.g. "en_GB" or "[email protected]")
- name: Optional. If left commented out, then KHolidayRegion::description() will default to the translation for the "country" code and optionally and category variant included in the file name. It is recommended to leave this to the default except for specialised category or global files where the generated default name is incorrect or insufficient.
- description: Optional but recommended. Provide a longer description of the file in the language of the file to be returned by KHolidayRegion::description(), for example "National holiday file for Spain" or "Catholic Saint's Days".
Holiday List Section
After the File Metadata comes the holiday rules themselves. A typical rule is of the format:
"[Holiday Name]" [categories] on [calendar] [calculation]
"New Years Day" public cultural on january 1 "Valentines Day" cultural on february 14 "Easter" religious on easter "Christmas Day" public religious on december 25 "Eid ul-Fitr" religious on hijri shawwal 1
You must assign at least one category to a holiday, and can assign multiple categories if needed.
The calendar is the calendar system to use in the date calculation, such as Gregorian or Hijri. If omitted then Gregorian is assumed.
Calculations can be a simple day and month, or very complex logical and mathematical expressions, or be relative to other events, or even be shifted to other dates.
For convenience, we organise the list into categories, with each category sorted in date order. All Public Holidays should go in the first section regardless of any other category they may belong to.
Holiday categories can be managed in a number of ways, primarily by the category keywords in the file format. Holidays can also be categorised by splitting them into separate files and adding the category name as a variant tag in the filename.
Holiday Category Tags
You must assign one or more category keywords to every holiday rule.
While the file format doesn't distinguish between different types of category tags or assign any special meaning to them, KHolidays does infer special meaning from certain tags:
- Most tags are "Group" Category tags, simply used to group holidays by type, such as Religious and Cultural.
- Some tags are "Day Off" Category tags used to indicate for whom a holiday is a day off work, such as Public or Government.
- A few tags are both "Group" and "Day Off" tags that are used to both group the holidays and indicate who gets the day off work, such as School.
This means that while in most cases a single category tag is all that is required for a holiday, some holidays will have a second "Day Off" category tag to indicate the group of people who get that day off work or school. By convention the "Day Off" tags should come first.
The following category keywords are currently supported by the file format.
- public - Day Off for all people in the administrative region, implies all other Day Off types as well
- government - Day Off for government workers only, can also be used as a group category if nothing else applies
- financial - Day Off for financial sector workers only, can also be used as a group category if nothing else applies
- school - Day Off for schools only, can also be used as a group category if nothing else applies
- civil - Holidays related to civil matters, e.g. national, state, government, royal, military, etc
- religious - Holidays related to religion
- cultural - Holidays related to regional, national or international culture, a general catch-all
- commemorative - Holidays related to commemorating solemn events, such as wars, deaths, etc.
- historical - Holidays related to historic events
- nameday - Holidays related to Name Days
- seasonal - Holidays related to the time of year, such as season changes and daylight savings
If you require other category tags please file a feature request.
Sometimes a national holiday file will hold too many holidays for a given category to be useful to most users, sometimes to the point that users will disable the file rather than have their calendar flooded with events. This usually applies to Religious holidays and Name Days. To prevent this you can split the holidays out into separate files that the user can then configure separately to display or not.
While it is recommended to keep each such file restricted to a single category, there is nothing to stop you mixing multiple categories in such a file. Where the file holds a single category then just append that category to the end of the filename (e.g. "holiday_es_es_religious") and KHolidays will automatically generate a Holiday Region Name including that category. If you mix the categories, or the generated name is not suitable, then populate teh "name" metadat field with the name you want.
The filename category supports extra categories for religions to allow for more detailed control over these holidays. The extra supported categories are:
- personal - A file containing your personal set of holidays
If you require other category tags please file a feature request.
There are very many clever tricks to calculate holidays, most of which have already been used, so have a look in the existing files for inspiration or to see if your holiday has already been implemented.
The simplest holiday rule is to simply state the day of the year that the holiday occurs on:
"New Years Day" public on january 1
You can define the calendar system to use in calculating a holiday
"Islamic New Year" civil on hijri muharram 1
You can also define how long a holiday lasts for:
"3 Day Holiday" public on july 1 length 3
There are special keywords available for Easter and Orthodox Easter:
"Easter Sunday" public on easter "Orthodox Easter Sunday" public on pascha
Other custom formulas can be supported in the same way if needed.
To calculate a holiday relative to another date:
"Good Friday" public religious on easter minus 2 "Easter Monday" public on easter plus 1
To calculate a holiday on a given weekday in a given week in a month:
"Early May Bank Holiday" public on first monday in may "British Summer Time starts" seasonal on last sunday in march
You can use conditionals to restrict the year range that a holiday applies to, or that a calculation for a holiday applies to. note that conditionals can be nested, but it is advised not to nest too deep or it becomes difficult to read and understand.
To restrict a calendar to a single year then stipulate that year:
"Royal Wedding" public on 29 april 2011
To set the date range a holiday applies to (e.g. if a new holiday is introduced or an old one ended, or the calculation is changed):
"Old Holiday" public on ((year <= 2012) ? [june 1] : [noop]) "New Holiday" public on ((year >= 2012) ? [may 1] : [noop]) "Spring Bank Holiday" public on ((year == 2012) ? [june 4] : [last monday in may])
If the calculation has changed too many times, the rule may get too complex, so you may want to express it as multiple rules instead.
If you need to apply different categories depending on the date:
"Nationaldagen" civil on ((year <= 2004) ? [june 6] : [noop]) "Nationaldagen" public on ((year >= 2005) ? [june 6] : [noop])
You can shift a holiday to another date if it meets certain conditions:
"New Year's Day" public on january 1 shift to monday if sunday
However this can get confusing if, as in this case, the original date really is the "holiday" and the shifted date is just the day off. You should only use this form if the actual holiday itself gets moved. An alternative could be:
"New Year's Day" cultural on january 1 "New Year's Day Holiday" public on january 1 shift to monday if sunday
The problem here is you always get to see two entries where one would be sufficient most years. You can use conditionals to calculate exactly when to display the extra holiday, but it gets complicated:
"News Years Day Holiday" public on ( (([january 1] == [sunday after ([january 1])])) ? [monday after ([january 1])] : noop )
To observe a holiday on the Monday if it falls on a Saturday or Sunday while keeping the original day off as well:
"Christmas Day" public religious on december 25 "Christmas Day Bank Holiday" public on ( (([december 25] == [saturday after ([december 25])]) || ([december 25] == [sunday after ([december 25])])) ? [monday after ([december 25])] : noop )