The KHolidays Library
The KHolidays library in kdepimlibs provides details on public holidays for a given country and date range. A separate library and file format is required as iCalendar is not capable of expressing recurrence rules for all possible holidays.
OpenHolidays GSOC Project
A GSOC 2014 project proposal to do the initial implementation has been submitted. This section documents the background reading required for candidates for this project. If you wish to apply for the project, please subscribe to the [email protected] mailing list and send your initial contact email there with a cc: to [email protected]
A good introduction to the project is the presentation done at the Berlin Desktop Summit in August 2011. Read through the slides from the talk to get the background.
Next, read through the contents of this wiki page and follow the various links, in particular:
- The current KHoliday library API
- The current KHoliday data files (but don't worry too much about understanding the file format)
- The various proposals for new file formats in XML and JSON
- Pay particular attention to the new OpenHolidays design notes
One compulsory requirement is to integrate the new QOpenHolidays library into KDE using the Akonadi PIM server in a manner similar to iCalendar files where a base event has a start and end date with recurrence dates able to be queried (KHolidays does not offer such an api).
- Learn some of the basics for the iCalendar design, in particular the relationship between base events and recurrences
- Learn some of the basics of the KCalCore library, KDE PIM's implementation of an iCal library, that QOpenHolidays should operate in a similar manner to.
- Learn some of the basics of Akonadi and how KCalCore integrates into it as a resource, which QOpenHolidays should operate in a similar manner to.
A major concern is the localization of the files, so you need some understanding of how the KDE localization system works.
It is recommended to get some familiarity with the KDE code development process by submitting some small bug fixes. In this case you could look in Bugzilla for KHolidays data file updates that need to be done.
- John Layt (IRC jlayt)
- Allen Winter
- API: Browse api.kde.org
- Code: Browse projects.kde.org
- Code: Browse quickgit.kde.org
- Bugs: Bugzilla Search
The following features are available in KHolidays that are not supported in iCalendar:
- Alternative calendar systems (Hebrew, Islamic, etc)
- Special date calculations, currently Easter and Orthodox Easter, but can include events like solstices, or any named day of the year.
- Commemoration date, i.e. Christmas occurs on a Sunday, you get the Monday off.
- Holiday Class, i.e.day-of,not day off, religious day off, school holiday, etc
- Holiday Categories, i.e. Cutural, Official, Religious, etc.
The file format originally used was the PLAN format, but this has been extended a number of times to support new features. The limits of the format have about been reached and it is too complex for easy maintenance. It is intended to add a few more features to the format then to design a new XML file format to replace it.
- Historic document: http://community.kde.org/KDE_PIM/KOrganizer/Holiday_File_Format
The following development plan is designed to become a Freedesktop.org project so that the maintenance burden can be shared with Gnome and any other interested parties.
- Design a new XML based file format
- Convert KDE files to new format
- Implement a base C (?) library to parse the XML file and calculate the holidays, will include calendar systems if not in glibc by then. No desktop specific code allowed, i.e. to be equivalent to libical.
- Implement a pure Qt library to wrap the C library in kdesupport
- Implement an Akonadi resource
Rough Notes From KHolidays TODO
- KHolidays: Holiday types, day-off types.
- Split the existing holiday files up into civil and religious files and create a better naming scheme including country, language, region and type.
- Finalise the required file metadata fields (name, region, language, etc).
- Add holiday class/category syntax (e.g. Public / Religious / Cultural / Financial Holiday etc). Holidays can have multiple classes/categories, implement as flags.
- Improve the SHIFT syntax to cater for more complex rules (e.g. the Boxing Day problem). Add optional name for day shifted to.
- Add a NOOP or EXCLUDE syntax to allow holidays to only occur in some years and not others.
- Solstice/Equinox keywords and functions (like Easter).
- If holiday has a duration > 1 day return only one Holiday instance with a duration and/or end date attribute set, rather than multiple Holiday instances. This will allow the client app to choose whether to display as a singled spanned entry or multiple entries, and may make de-duping easier.
- Return attributes of both original date of holiday and shifted to observation date, and if original date is still a holiday or not. Option to have different names shown for each date.
- Try sort out translation of the file names, the desktop file might be the way to go.
- Hebrew special event calculations
- So would that mean HolidayRegion::locations() (or the equivalent) could be passed an argument that means it will only return those locations that have holiday files of a particular type (e.g. civil)?
- Any plans to add a way of selecting holiday calendars to the KDE Control Module (Country/Region & Language)?
- I think we would have to have 2 sets, a top-level or global faith/language set, then a region/faith/language set for local variations (where faith means a religion or any sub-set within that religion). For the top-level the filename itself would just use a region code of xx which is the ISO code for supra-national groups. So something like holiday_xx_es_catholic with a metadata display name of "Catholic (Spanish)" and holiday_ar_es_catholic with "Argentine Catholic (Spanish)".
- The design actually has a nice directory based hierarchy for this, I'll have a think if we want to do that yet.
- allow them to choose to display multiple holiday files at the same time to know which is their 'official' holiday file for days-off to show in red, and if they select a second civil region to display those days-off won't be marked in red but in blue for information only. But that might be a per-file setting, someone might want both sets of days off!
- Some control over what colours are used will be needed too.
1 <holiday predefined="christmas" region="GB" type="public,religious"> 2 <observance move-type="both-days" days-off="both-days" language="en_GB">Christmas Day Bank Holiday</observance> 3 </holiday> 4 5 <holiday region=NZ_WN type="public"> 6 <name language="en_NZ">Wellington Anniversary Day</name> 7 <observance calendar="gregorian" month="01" day="22" started="1853" /> 8 </holiday>
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE holidayCalendar > 3 4 <!-- US Federal Holidays --> 5 6 7 <!-- Federal Holidays in The United States --> 8 <holidayCalendar name="Federal" type="political"> 9 10 11 <-- New Year's Day --> 12 <holiday type="public" workDayOff="true" schoolDayOff="true"> 13 <name>New Year's Day</name> 14 <datespec> 15 <posdate position="fourth" dayOfWeek="thursday" month="11"> 16 <plus days="1"/> 17 </posdate> 18 </datespec> 19 <description>Start of year, marks traditional end of holiday season</description> 20 </holiday> 21 22 </holidayCalendar> 23 24 <?xml version="1.0" encoding="UTF-8"?> 25 <!DOCTYPE features > 26 27 <!-- Maryland State Holidays 28 29 Includes all the federal holidays plus 30 Election Day (even years only) 31 Day After Thanksgiving 32 --> 33 34 <!-- Holidays for the state of Maryland in The United States --> 35 <holidayCalendar name="Maryland" type="political"> 36 <include>UnitedStates/Federal.xml</include> 37 38 <holiday type="public" workDayOff="true" schoolDayOff="true"> 39 <name>Day After Thanksgiving</name> 40 <datespec> 41 <posdate position="fourth" dayOfWeek="thursday" month="11"> 42 <plus days="1"/> 43 </posdate> 44 </datespec> 45 <description>The day after Thanksgiving</description> 46 </holiday> 47 48 <holiday type="public" workDayOff="true" schoolDayOff="true"> 49 <name>Election Day</name> 50 <datespec> 51 <posdate position="first" dayOfWeek="tuesday" month="11"> 52 <yearMod>2</yearMod> <!-- every even year --> 53 </posdate> 54 </datespec> 55 <description>Election Day</description> 56 </holiday> 57 58 </holidayCalendar>
Rough Notes from OpenHolidays Design at KDE PIM Sprint Brno 2013
The OpenHolidays Project
A project to implement a common file format, data repository, and reference libraries for national holiday data. A core goal is to develop a cross-platform community to maintain the Holidays data in a manner similar to the Time Zone database or iso-codes project, and for the data to be available to be used everywhere.
Implementation goals include:
- A JSON file format for rules for calculating holidays and for distributing calculated holidays
- A web service to query for the rule files or the calculated holidays
- A JS reference library implementation for use by websites and apps
- A C library implementation (using ICU for calendars?)
- A Qt library implementation
- Akonadi integration
- A GUI utility for developers and users to create custom holiday files
- Best licence for the data? CC-0? Technically is aggregation of facts, individual facts not protected by copyright, but database could be deemed to be copyrighted.
- Is JSON the best format? Issues with comments and localization?
Three forms of the file:
- Unresolved: the raw or master data files containing the generic rules parts of which may be spread across generic resource files
- Partly resolved: A standalone file containing all the information required to calculate the rules, i.e. all includes have been merged and simplified
- Fully resolved: The specific occurrences of the holidays in a given time period
First design resolved format, i.e. what the Qt api will deliver
Key attributes like name, calendar, etc can be overridden in sub-clauses, or derived from first parent, i.e the core recurrence rule entity can fully specify all details required, but where these are common to multiple recurrence rules they can be omitted from the recurrence rule and defined at a holiday or resource level, or even imported
calendar - gregorian - julian - etc
HolidayOccurrence - official name - common name - observance name - occurrence start datetime - occurrence end datetime - observance start datetime - observance end datetime - observance type - isWholeDay - isMultiDay
The master files will be defined in en_US for convenience of maintenance. The format will support optional in-file translated strings for fully-resolved format, or custom non-resolved format, but the master files will only include translations for the the official names for regional files for the languages used in that region. This is to keep the file from bloating and being hard to maintain, and to keep the official local names properly controlled. The master files will use standard .po files and the KDE translation framework for allother languages. The standard English strings will be extracted and translated into all other languages using gettext, but scripting will be provided to generate Qt tr and json format translation files from these. The extraction script will also extract the official names and pre-populate the po files for those languages. The web service may offer the ability to inline all available languages on request, or to serve the required po or json tr file.
Resource File Hierarchy
Definition of the default master database file hierarchy, designed to minimise duplication. A fully resolved file may contain elements form many of the master files.
Top level directory holds a set of generic holiday rule files named by their primary category. These are common defined date and name rules that are commonly used by many files. For example, Christmas Day, New Years Day, Valentines Day, Easter, etc. These files only hold the default English name. These files can be included into regional files and the rule extended by any local variations, e.g. define if Easter is a public holiday or not.
The regional files are organised by directories by ISO country code, with subdirs for ISO regional codes if there are sufficient regional variations to warrant a separate file. Each country directory may have one or more files for the different primary categories, or a single file if there are only a few holidays and separate files seem over-kill. These files can have official local name translations held in them. It is strongly
Categories: - Official - Civil - Cultural - NameDay - Religious - Catholic - Orthodox - Protestant - Islamic - Jewish Orthodox - Jewish Reform - etc
DaysOff: - PublicDayOff - Implies all other? - GovernmentDayOff - SchoolDayOff - FinancialDayOff
Base file hierarchy: /civil.json /cultural.json /financial.json /catholic.json /protestant.json /orthodox.json /islamic.json /GB/EAW/official.json /GB/EAW/catholic.json /GB/EAW/cultural.json /NZ/civil.json
Include versus Import
Including another file makes the other files holidays rules available to be extended, but for the holidays to be included in the fully-realised file must be explicitly extended.
Importing another file causes all the other files rules to be included in the fully-realised file.
JSON cannot have inline comments, but we need to document the rules and sources for the rules in the master files. This will be done via a Source object containing any comments and links required. Shipping this info in the partly or fully resolved files would be wasteful, so the resolving process will strip the Source object out.
School Holidays - Best done with iCal? Are they predictable enough? Maybe only historic and current, no future?
HolidayResource - HolidayEvent - HolidayOccurrence
The HolidayResource is a set of holiday calculation rules The HolidayEvent is the holiday calculation rule The HolidayOccurrence is an actual occurrence of a holiday on an actual date
The HolidayResource can return the set of HolidayEvent active between two dates The HolidayResource can return the set of HolidayOccurrence between two dates for all HolidayEvent in the HolidayResource The HolidayEvent can return the set of HolidayOccurrence between two dates for itself The HolidayOccurrence only knows about itself
Event () QDate dateEnd () const virtual KDateTime dtEnd () const bool hasEndDate () const QLatin1String iconName (const KDateTime &recurrenceId=KDateTime()) const bool isMultiDay (const KDateTime::Spec &spec=KDateTime::Spec()) const QLatin1String mimeType () const virtual void shiftTimes (const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec) Transparency transparency () const IncidenceType type () const QByteArray typeStr () const
Incidence () Alarm::List alarms () const QString altDescription () const Attachment::List attachments () const Attachment::List attachments (const QString &mime) const QStringList categories () const QString categoriesStr () const KDateTime created () const QString customStatus () const QString description () const bool descriptionIsRich () const virtual KDateTime endDateForStart (const KDateTime &startDt) const float geoLatitude () const float geoLongitude () const bool hasAltDescription () const bool hasEnabledAlarms () const bool hasGeo () const bool hasRecurrenceId () const QString instanceIdentifier () const bool localOnly () const QString location () const bool locationIsRich () const Alarm::Ptr newAlarm () int priority () const void recreate () Recurrence * recurrence () const KDateTime recurrenceId () const ushort recurrenceType () const virtual void recurrenceUpdated (Recurrence *recurrence) bool recurs () const bool recursAt (const KDateTime &dt) const virtual bool recursOn (const QDate &date, const KDateTime::Spec &timeSpec) const QString relatedTo (RelType relType=RelTypeParent) const void removeAlarm (const Alarm::Ptr &alarm) QStringList resources () const int revision () const QString richDescription () const QString richLocation () const QString richSummary () const QString schedulingID () const Secrecy secrecy () const virtual QList< KDateTime > startDateTimesForDate (const QDate &date, const KDateTime::Spec &timeSpec=KDateTime::LocalZone) const virtual QList< KDateTime > startDateTimesForDateTime (const KDateTime &datetime) const Status status () const QString summary () const bool summaryIsRich () const bool supportsGroupwareCommunication () const bool thisAndFuture () const QString writeAttachmentToTempFile (const Attachment::Ptr &attachment) const
IncidenceBase () bool allDay () const QStringList comments () const QStringList contacts () const virtual KDateTime dtStart () const Duration duration () const bool hasDuration () const