Welcome | Get started | Dive into Lino | Contribute | Reference | More

Defining holidays

The lino_xl.lib.cal plugin also adds functionality for managing holidays and birthdays.

Some initialization:

>>> from lino import startup
>>> startup('lino_book.projects.min9.settings')
>>> from lino.api.doctest import *
>>> settings.SITE.verbose_client_info_message = True
>>> from lino.api import rt, _
>>> from atelier.utils import i2d
>>> RecurrentEvent = cal.RecurrentEvent
>>> Recurrences = cal.Recurrences

Recurrent events

A series of standard holidays are defined as recurrent events by the std fixture of lino_xl.lib.cal:

>>> rt.show(cal.RecurrentEvents)
============ ========== ============================ ===================== =================================== ==================== =====================
 Start date   End Date   Designation                  Designation (de)      Designation (fr)                    Recurrence           Calendar entry type
------------ ---------- ---------------------------- --------------------- ----------------------------------- -------------------- ---------------------
 01/01/2013              New Year's Day               Neujahr               Jour de l'an                        yearly               Holidays
 11/02/2013              Rosenmontag                  Rosenmontag           Lundi de carnaval                   Relative to Easter   Holidays
 13/02/2013              Ash Wednesday                Aschermittwoch        Mercredi des Cendres                Relative to Easter   Holidays
 29/03/2013              Good Friday                  Karfreitag            Vendredi Saint                      Relative to Easter   Holidays
 31/03/2013              Easter sunday                Ostersonntag          Pâques                              Relative to Easter   Holidays
 01/04/2013              Easter monday                Ostermontag           Lundi de Pâques                     Relative to Easter   Holidays
 01/05/2013              International Workers' Day   Tag der Arbeit        Premier Mai                         yearly               Holidays
 09/05/2013              Ascension of Jesus           Christi Himmelfahrt   Ascension                           Relative to Easter   Holidays
 20/05/2013              Pentecost                    Pfingsten             Pentecôte                           Relative to Easter   Holidays
 21/07/2013              National Day                 Nationalfeiertag      Fête nationale                      yearly               Holidays
 15/08/2013              Assumption of Mary           Mariä Himmelfahrt     Assomption de Marie                 yearly               Holidays
 31/10/2013              All Souls' Day               Allerseelen           Commémoration des fidèles défunts   yearly               Holidays
 01/11/2013              All Saints' Day              Allerheiligen         Toussaint                           yearly               Holidays
 11/11/2013              Armistice with Germany       Waffenstillstand      Armistice                           yearly               Holidays
 25/12/2013              Christmas                    Weihnachten           Noël                                yearly               Holidays
============ ========== ============================ ===================== =================================== ==================== =====================

Relative to Easter

Certain recurrent events are relative to Easter. Let's look at one of them, Ash Wednesday:

>>> ash = RecurrentEvent.objects.get(name="Ash Wednesday")

The std fixture of lino_xl.lib.cal generates automatically all Ash Wednesdays for a range of years:

>>> rt.show(cal.EntriesByController, master_instance=ash, nosummary=True)
================ =================== ================= ===== ================== =====================
 When             Short description   Workflow          No.   Responsible user   Calendar entry type
---------------- ------------------- ----------------- ----- ------------------ ---------------------
 Wed 06/03/2019   Ash Wednesday       **? Suggested**   7                        Holidays
 Wed 14/02/2018   Ash Wednesday       **? Suggested**   6                        Holidays
 Wed 01/03/2017   Ash Wednesday       **? Suggested**   5                        Holidays
 Wed 10/02/2016   Ash Wednesday       **? Suggested**   4                        Holidays
 Wed 18/02/2015   Ash Wednesday       **? Suggested**   3                        Holidays
 Wed 05/03/2014   Ash Wednesday       **? Suggested**   2                        Holidays
================ =================== ================= ===== ================== =====================

Actually the user sees just the summary:

>>> rt.show(cal.EntriesByController, master_instance=ash)
March 2019: *Wed 06.*?
February 2018: *Wed 14.*?
March 2017: *Wed 01.*?
February 2016: *Wed 10.*?
February 2015: *Wed 18.*?
March 2014: *Wed 05.*?
Suggested : 6 ,  Draft : 0 ,  Published : 0 ,  Took place : 0 ,  Cancelled : 0

That range of years depends on some configuration variables:

  • ignore_dates_before

  • ignore_dates_after

  • lino.modlib.system.SiteConfig.max_auto_events

  • the_demo_date

>>> dd.plugins.cal.ignore_dates_before
>>> dd.plugins.cal.ignore_dates_after
datetime.date(2019, 10, 23)
>>> settings.SITE.site_config.max_auto_events
72
>>> settings.SITE.the_demo_date
datetime.date(2014, 10, 23)

Manually creating moving feasts

The recurrency rules for moving feasts have their every_unit field set to easter.

Lino then computes the offset (number of days) between your start_date and the Easter date of the start year, and generates subsequent events by moving their date so that the offset remains the same.

Lino uses the easter() function of dateutil for getting the Easter date.

>>> from dateutil.easter import easter
>>> easter(2015)
datetime.date(2015, 4, 5)

Adding a local moving feast

We can add our own local custom holidays which depend on easter.

We create a recurrency rule for it, specifying easter in their every_unit field.

>>> holidays = cal.EventType.objects.get(**dd.str2kw('name', _("Holidays")))
>>> obj = RecurrentEvent(name="Karneval in Kettenis",
...     every_unit=Recurrences.easter,
...     start_date=i2d(20160209), event_type=holidays)
>>> obj.full_clean()
>>> obj.find_start_date(i2d(20160209))
datetime.date(2016, 2, 9)
>>> set_log_level(logging.DEBUG)
>>> ar = rt.login()
>>> wanted, unwanted = obj.get_wanted_auto_events(ar)
... 
Generating events between 2016-02-09 and 2019-10-23 (max. 72).
Reached upper date limit 2019-10-23 for 4
>>> len(wanted)
4
>>> wanted[0]  
Event(start_date=2016-02-09,owner_type=...,summary='Karneval in Kettenis',auto_type=1,priority=<xl.Priorities.normal:30>,event_type=2,state=<cal.EntryStates.suggested:10>,notify_unit=<cal.NotifyBeforeUnits.minutes:10>)