From f59e4d2889d6f097e8ce889a04e70bbeb736da5d Mon Sep 17 00:00:00 2001 From: SNoiraud Date: Sun, 26 Dec 2021 10:05:48 +0100 Subject: [PATCH] Display leap day anniversaries every year on calendars Added a new anniversary method to dates which returns a day and month on which to display leap day anniversaries on non-leap years. Added an option in the preferences display tab which allows the user to specify on which day the anniversary should be displayed. The options are: 28th Feb, 1st Mar or only on 29th Feb. Fixes #12511 --- gramps/gen/config.py | 1 + gramps/gen/lib/date.py | 19 +++++++++++ gramps/gen/lib/test/date_test.py | 35 +++++++++++++++++++++ gramps/gui/configure.py | 23 ++++++++++++++ gramps/plugins/drawreport/calendarreport.py | 2 ++ gramps/plugins/textreport/birthdayreport.py | 6 ++-- gramps/plugins/webreport/calendar.py | 3 +- gramps/plugins/webreport/webcal.py | 2 +- 8 files changed, 87 insertions(+), 4 deletions(-) diff --git a/gramps/gen/config.py b/gramps/gen/config.py index 6ea404ab85b..b02c4e6627b 100644 --- a/gramps/gen/config.py +++ b/gramps/gen/config.py @@ -250,6 +250,7 @@ def emit(key): register('preferences.date-format', 0) register('preferences.calendar-format-report', 0) register('preferences.calendar-format-input', 0) +register('preferences.february-29', 0) # 0: 02/28; 1: 03/01; 2: only the 02/29 register('preferences.cprefix', 'C%04d') register('preferences.default-source', False) register('preferences.tag-on-import', False) diff --git a/gramps/gen/lib/date.py b/gramps/gen/lib/date.py index 78870982f55..496dc2df07a 100644 --- a/gramps/gen/lib/date.py +++ b/gramps/gen/lib/date.py @@ -30,6 +30,7 @@ # # ------------------------------------------------------------------------ import logging +import calendar # ------------------------------------------------------------------------- # @@ -2064,6 +2065,24 @@ def make_vague(self): self.dateval = tuple(dlist) self._calc_sort_value() + def anniversary(self, year): + """ + If the date is February 29, you must choose the day to view it in the + event of a non-leap year. + This is usualy used in calendars. + """ + month = self.dateval[Date._POS_MON] + day = self.dateval[Date._POS_DAY] + if month == 2 and day == 29 and not calendar.isleap(year): + day_show = config.get('preferences.february-29') + if day_show == 0: + day = 28 + elif day_show == 1: + month = 3 + day = 1 + # else: # In all other cases, keep the february 29 day + return (month, day) + year = property(get_year, set_year) diff --git a/gramps/gen/lib/test/date_test.py b/gramps/gen/lib/test/date_test.py index 03a6f335926..fe608ca57ac 100644 --- a/gramps/gen/lib/test/date_test.py +++ b/gramps/gen/lib/test/date_test.py @@ -1232,6 +1232,41 @@ def test_span_empty(self): d.set(value=(1, 1, 1900, False, 1, 1, 1910, False), modifier=Date.MOD_SPAN) self.assertFalse(d.is_empty()) +# ------------------------------------------------------------------------- +# +# AnniversaryDateTest +# +# ------------------------------------------------------------------------- +class AnniversaryDateTest(BaseDateTest): + """ + Tests for leap day anniversary dates. + """ + + def test_leapyear_1(self): + config.set('preferences.february-29', 0) + d = Date(1904, 2, 29) + self.assertEqual(d.anniversary(1908), (2, 29)) + + def test_leapyear_2(self): + config.set('preferences.february-29', 1) + d = Date(1904, 2, 29) + self.assertEqual(d.anniversary(1908), (2, 29)) + + def test_nonleapyear_before(self): + config.set('preferences.february-29', 0) + d = Date(1904, 2, 29) + self.assertEqual(d.anniversary(1910), (2, 28)) + + def test_nonleapyear_after(self): + config.set('preferences.february-29', 1) + d = Date(1904, 2, 29) + self.assertEqual(d.anniversary(1910), (3, 1)) + + def test_nonleapyear_keep(self): + config.set('preferences.february-29', 2) + d = Date(1904, 2, 29) + self.assertEqual(d.anniversary(1910), (2, 29)) + if __name__ == "__main__": unittest.main() diff --git a/gramps/gui/configure.py b/gramps/gui/configure.py index 8d45c8bc2ad..f1e432fda99 100644 --- a/gramps/gui/configure.py +++ b/gramps/gui/configure.py @@ -1386,6 +1386,23 @@ def add_data_panel(self, configdialog): grid.attach(lwidget, 1, row, 1, 1) grid.attach(obox, 2, row, 2, 1) + row += 1 + # Birthday on february 29 + feb29 = Gtk.ComboBoxText() + show_on = [_("on the previous day"), + _("on the next day"), + _("only on leap years")] + list(map(feb29.append_text, show_on)) + active = config.get('preferences.february-29') + feb29.set_active(active) + feb29.connect('changed', self.date_february_29_display_on) + ttip = _("For non leap years, anniversaries are displayed on either " + "February 28, March 1 or not at all in Gregorian calendars") + feb29.set_tooltip_text(ttip) + lwidget = BasicLabel(_("Show leap day anniversaries")) + grid.attach(lwidget, 1, row, 1, 1) + grid.attach(feb29, 2, row, 2, 1) + row += 1 # Status bar: obox = Gtk.ComboBoxText() @@ -1572,6 +1589,12 @@ def date_calendar_for_input_changed(self, obj): """ config.set('preferences.calendar-format-input', obj.get_active()) + def date_february_29_display_on(self, obj): + """ + Save "February 29 display on " option. + """ + config.set('preferences.february-29', obj.get_active()) + def autobackup_changed(self, obj): """ Save "Autobackup" option on change. diff --git a/gramps/plugins/drawreport/calendarreport.py b/gramps/plugins/drawreport/calendarreport.py index a932a9eeb93..af42935c0f5 100644 --- a/gramps/plugins/drawreport/calendarreport.py +++ b/gramps/plugins/drawreport/calendarreport.py @@ -28,6 +28,7 @@ import datetime import time from functools import partial +import calendar #------------------------------------------------------------------------ # @@ -374,6 +375,7 @@ def get_surname_of_husband(): day = birth_date.get_day() prob_alive_date = Date(self.year, month, day) + month, day = birth_date.anniversary(self.year) nyears = self.year - year short_name = self.get_name( diff --git a/gramps/plugins/textreport/birthdayreport.py b/gramps/plugins/textreport/birthdayreport.py index eb62bc940ed..aed2a79a397 100644 --- a/gramps/plugins/textreport/birthdayreport.py +++ b/gramps/plugins/textreport/birthdayreport.py @@ -27,6 +27,7 @@ # #------------------------------------------------------------------------ import datetime, time +import calendar #------------------------------------------------------------------------ # @@ -37,8 +38,9 @@ _ = glocale.translation.gettext from gramps.gen.const import URL_HOMEPAGE from gramps.gen.errors import ReportError +from gramps.gen.config import config from gramps.gen.lib import NameType, EventType, Name, Date, Person, Surname -from gramps.gen.lib.date import gregorian +from gramps.gen.lib.date import gregorian, Today from gramps.gen.relationship import get_relationship_calculator from gramps.gen.plug.docgen import (FontStyle, ParagraphStyle, GraphicsStyle, FONT_SERIF, PARA_ALIGN_RIGHT, @@ -291,7 +293,7 @@ def collect_data(self): day = birth_date.get_day() prob_alive_date = Date(self.year, month, day) - + month, day = birth_date.anniversary(self.year) nyears = self.year - year # add some things to handle maiden name: father_lastname = None # husband, actually diff --git a/gramps/plugins/webreport/calendar.py b/gramps/plugins/webreport/calendar.py index 064173f1744..05960325ce8 100644 --- a/gramps/plugins/webreport/calendar.py +++ b/gramps/plugins/webreport/calendar.py @@ -968,7 +968,7 @@ def collect_data(self, this_year): # current year of calendar, month nd day is their birth # month and birth day prob_alive_date = Date(this_year, month, day) - + month, day = birth_date.anniversary(this_year) # add some things to handle maiden name: father_surname = None # husband, actually if person.gender == Person.FEMALE: @@ -1093,6 +1093,7 @@ def collect_data(self, this_year): month = event_date.get_month() day = event_date.get_day() + month, day = event_date.anniversary(this_year) # date to figure if someone is still alive prob_alive_date = Date(this_year, month, day) diff --git a/gramps/plugins/webreport/webcal.py b/gramps/plugins/webreport/webcal.py index 6dd61d4dece..94c93867bcb 100644 --- a/gramps/plugins/webreport/webcal.py +++ b/gramps/plugins/webreport/webcal.py @@ -1370,7 +1370,7 @@ def collect_data(self, this_year): # current year of calendar, month nd day is their birth # month and birth day prob_alive_date = Date(this_year, month, day) - + month, day = birth_date.anniversary(this_year) # add some things to handle maiden name: father_surname = None # husband, actually if person.gender == Person.FEMALE: