Jump to content

KDE PIM/KHolidays

From KDE Community Wiki

The KHolidays Library

Introduction

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.

Maintainers

  • John Layt (IRC jlayt)
  • Allen Winter

Resources

Features

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.

File Format

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.

Future Plans


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


A proposal was presented at the Berlin Desktop Summit in August 2011. The slides from the talk go into more detail.

Rough Notes From KHolidays TODO

KHolidays

  • 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.


<holiday predefined="christmas" region="GB" type="public,religious">
  <observance move-type="both-days" days-off="both-days" language="en_GB">Christmas Day Bank Holiday</observance>
</holiday>

<holiday region=NZ_WN type="public">
  <name language="en_NZ">Wellington Anniversary Day</name>
  <observance calendar="gregorian" month="01" day="22" started="1853" />
</holiday>


Old design:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE holidayCalendar >

<!-- US Federal Holidays -->


<!-- Federal Holidays in The United States -->
<holidayCalendar name="Federal" type="political">

  
<-- New Year's Day -->
  <holiday type="public" workDayOff="true" schoolDayOff="true">
    <name>New Year's Day</name>
    <datespec>
      <posdate position="fourth" dayOfWeek="thursday" month="11">
        <plus days="1"/>
      </posdate>
    </datespec>
    <description>Start of year, marks traditional end of holiday season</description>
  </holiday>

</holidayCalendar>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE features >

<!-- Maryland State Holidays

     Includes all the federal holidays plus
       Election Day (even years only)
       Day After Thanksgiving
-->

<!-- Holidays for the state of Maryland in The United States -->
<holidayCalendar name="Maryland" type="political">
  <include>UnitedStates/Federal.xml</include>

  <holiday type="public" workDayOff="true" schoolDayOff="true">
    <name>Day After Thanksgiving</name>
    <datespec>
      <posdate position="fourth" dayOfWeek="thursday" month="11">
        <plus days="1"/>
      </posdate>
    </datespec>
    <description>The day after Thanksgiving</description>
  </holiday>

  <holiday type="public" workDayOff="true" schoolDayOff="true">
    <name>Election Day</name>
    <datespec>
      <posdate position="first" dayOfWeek="tuesday" month="11">
        <yearMod>2</yearMod>  <!-- every even year -->
      </posdate>
    </datespec>
    <description>Election Day</description>
  </holiday>

</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

Q's

  • 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.

File Format

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

Translations

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.

Comments

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.

Excluded

School Holidays - Best done with iCal? Are they predictable enough? Maybe only historic and current, no future?

Object Hierarchy

 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

iCal Incidence

 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