I have developed my own version of a script for calculating birth and death dates based on the following information:
- Known events of the current individual
- Marriages
- Information about children
- Information about parents
- Information about partners
In addition to the calculation, the script also automatically updates existing birth and death events. Only events without dates are updated by the script. Existing dates remain unchanged. Personally, this saved me a lot of time because I had around 2k births and around 4.5k deaths without dates.
I want to note that for the calculation, I only used years and ignored months and days. I believe that approximate calculations should not include months or days. However, someone might think differently. For this reason, I think the âVerify the Dataâ utility will mark my calculated dates as errors because if, for example, a person was born on 1800-03-05, and the calculation estimates that they died around after 1800, then we know that 1800 is equivalent to 1800-00-00, which is less than 1800-03-05. But for me personally, this is acceptable.
I donât consider my script aesthetically pleasing, and itâs not optimized (this is my first experiense). Iâm sharing it only because someone might need some fragments of it for personal tasks, even if they will not be used as intended.
[Gramps SuperTool script file]
version=1
[title]
Update birth and death dates
[description]
# This script is designed to automatically update event dates (birth and death) in a database based on other events indicating approximate times
# of these events. It utilizes information about various event types (birth, death, marriage, etc.) as well as the roles of participants in these
# events to determine approximate birth and death dates for individuals in the database. Additionally, the script automatically synchronizes
# birth and death dates and updates the corresponding events in the database accordingly.
# The following information is utilized for calculating dates:
# - Known events of the current individual
# - Marriages
# - Information about children
# - Information about parents
# - Information about partners
[category]
People
[initial_statements]
# Initialization of constants for date modifiers and qualities
MOD_NONE = 0
MOD_BEFORE = 1
MOD_AFTER = 2
MOD_ABOUT = 3
MOD_RANGE = 4
MOD_SPAN = 5
MOD_TEXTONLY = 6
QUAL_NONE = 0
QUAL_ESTIMATED = 1
QUAL_CALCULATED = 2
# A note with comment inside like: "This event data was updated automatically with a SuperTool script"
auto_update_note = db.get_note_from_gramps_id("N1823")
# Dictionary to store calculated dates for each person
people_calculated_dates = {}
# Function to retrieve events from event proxies
def get_events(event_proxies):
results = []
for event_proxy in event_proxies:
results.append(event_proxy.obj)
return results
# Function to extract the year from a date object
def get_date(date):
if date.is_regular() or (date.get_year_valid() and date.get_modifier() in [MOD_NONE, MOD_ABOUT]):
return date.get_year()
else:
return None
# Function to retrieve the role of a person in an event
def get_role(person, db, referrer_handle, event_handle):
person = db.get_person_from_handle(referrer_handle)
eventref_list = person.get_event_ref_list()
for eventref in eventref_list:
if eventref.ref == event_handle:
return eventref.role
return None
# Function to get the larger of two values
def get_larger(a, b):
if a is None and b is None:
return None
elif a is None:
return b
elif b is None:
return a
else:
return a if a > b else b
# Function to get the smaller of two values
def get_less(a, b):
if a is None and b is None:
return None
elif a is None:
return b
elif b is None:
return a
else:
return a if a < b else b
# Function to update birth dates based on event type and role
def update_birth_dates(person_dates, date, offset_from, offset_to):
if not person_dates["birth"]["has_exact_date"]:
if offset_from is not None:
person_dates["birth"]["from"] = get_larger(person_dates["birth"]["from"], date + offset_from)
if offset_to is not None:
person_dates["birth"]["to"] = get_less(person_dates["birth"]["to"], date + offset_to)
# Function to update death dates based on event type and role
def update_death_dates(person_dates, date, offset_from, offset_to):
if not person_dates["death"]["has_exact_date"]:
if offset_from is not None:
person_dates["death"]["from"] = get_larger(person_dates["death"]["from"], date + offset_from)
if offset_to is not None:
person_dates["death"]["to"] = get_less(person_dates["death"]["to"], date + offset_to)
# Function to calculate events for a person
def calcPersonEvents(curr_person):
person_calculated_dates = {
"birth": {"from": None, "to": None, "has_exact_date": False},
"death": {"from": None, "to": None, "has_exact_date": False}
}
person_events = get_events(curr_person.events)
for event in person_events:
date = event.get_date_object()
person_obj = db.get_person_from_handle(curr_person.handle)
role = get_role(person_obj, db, curr_person.handle, event.handle)
date = get_date(date)
if date is None:
continue
if event.get_type() == "Baptism" and role == "Primary":
continue
if event.get_type() in ["Burial", "Military Service"]:
continue
if event.get_type() == "Birth" and role in ["Primary"]:
update_birth_dates(person_calculated_dates, date, 0, 0)
person_calculated_dates["birth"]["has_exact_date"] = True
update_death_dates(person_calculated_dates, date, 0, 100)
elif event.get_type() == "Death" and role in ["Primary"]:
update_death_dates(person_calculated_dates, date, 0, 0)
person_calculated_dates["death"]["has_exact_date"] = True
update_birth_dates(person_calculated_dates, date, -100, 0)
elif event.get_type() == "Marriage" and role == "Witness for":
update_birth_dates(person_calculated_dates, date, -65, -16)
update_death_dates(person_calculated_dates, date, 0, 100-16)
elif event.get_type() == "Baptism" and role in ["Godparent", "Godparent conditional"]:
update_birth_dates(person_calculated_dates, date, -65, -13)
update_death_dates(person_calculated_dates, date, 0, 100-13)
elif event.get_type() in ["Residence", "Census"] and role in ["Primary"]:
update_birth_dates(person_calculated_dates, date, -100, 0)
update_death_dates(person_calculated_dates, date, 0, 100)
elif event.get_type() in ["Mention"] and role in ["Primary", "Recipient"]:
update_birth_dates(person_calculated_dates, date, -100, 0)
update_death_dates(person_calculated_dates, date, 0, 100)
elif event.get_type() in ["Birth", "Death", "Mention"] and role in ["Applicant for (ĐĐ°ŃĐČĐœĐžĐș)"]:
update_birth_dates(person_calculated_dates, date, -80, -16)
update_death_dates(person_calculated_dates, date, 0, 100-16)
elif role == "Primary":
update_birth_dates(person_calculated_dates, date, -100, 0)
update_death_dates(person_calculated_dates, date, 0, 100)
else:
print(gramps_id, date, role, event.get_type())
return person_calculated_dates
# Function to calculate events for a person's family
def calcPersonFamily(personFamily, person_calculated_dates):
family_events = get_events(personFamily.events)
for event in family_events:
date = event.get_date_object()
date = get_date(date)
if date is None:
continue
if event.get_type() == "Marriage":
update_birth_dates(person_calculated_dates, date, -70, -16)
update_death_dates(person_calculated_dates, date, 0, 100-16)
elif event.get_type() == "Divorce":
update_birth_dates(person_calculated_dates, date, -70, -16)
update_death_dates(person_calculated_dates, date, 0, 100-16)
else:
print(event.get_type())
return person_calculated_dates
# Function to widen birth and death date ranges
def wideDates(dates, minus, plus):
if dates['birth']['from'] and dates['birth']['to']:
dates['birth']['from'] = dates['birth']['from'] + minus
dates['birth']['to'] = dates['birth']['to'] + plus
else:
dates['birth']['from'] = None
dates['birth']['to'] = None
if dates['death']['from'] and dates['death']['to']:
dates['death']['from'] = dates['death']['from'] + minus
dates['death']['to'] = dates['death']['to'] + plus
else:
dates['death']['from'] = None
dates['death']['to'] = None
return dates
# Function to combine birth dates from main and correction dates
def combineBirth(main_dates, correction_dates):
if not correction_dates['birth']['from'] or not correction_dates['birth']['to']:
return main_dates
if main_dates['birth']['has_exact_date']:
return main_dates
if not main_dates['birth']['from']:
main_dates['birth']['from'] = correction_dates['birth']['from']
if not main_dates['birth']['to']:
main_dates['birth']['to'] = correction_dates['birth']['to']
if main_dates['birth']['from']:
main_dates['birth']['from'] = get_larger(main_dates['birth']['from'], correction_dates['birth']['from'])
if main_dates['birth']['to']:
main_dates['birth']['to'] = get_less(main_dates['birth']['to'], correction_dates['birth']['to'])
return main_dates
# Function to update birth event with calculated dates
def updateBirthEvent(dates):
birth_obj = birth.obj
birth_date = birth_obj.get_date_object()
birth_from = dates['birth'].get('from')
birth_to = dates['birth'].get('to')
if birth_from is None or birth_to is None:
return
if birth_from > birth_to:
return
if not birth_date.is_empty():
return
birth_obj.add_note(auto_update_note.handle)
if birth_from == birth_to:
birth_date.set(
quality=Date.QUAL_CALCULATED,
value=(0, 0, birth_from, False)
)
else:
birth_date.set(
quality=Date.QUAL_CALCULATED,
modifier=Date.MOD_RANGE,
value=(0, 0, birth_from, False, 0, 0, birth_to, False)
)
birth_obj.set_date_object(birth_date)
db.commit_event(birth_obj, trans)
# Function to update death event with calculated dates
def updateDeathEvent(dates):
death_obj = death.obj
death_date = death_obj.get_date_object()
death_from = dates['death'].get('from')
death_to = dates['death'].get('to')
if death_from is None or death_to is None:
return
if death_from > death_to:
return
if not death_date.is_empty():
return
death_obj.add_note(auto_update_note.handle)
if death_from == death_to:
death_date.set(
quality=Date.QUAL_CALCULATED,
value=(0, 0, death_from, False)
)
else:
death_date.set(
quality=Date.QUAL_CALCULATED,
modifier=Date.MOD_RANGE,
value=(0, 0, death_from, False, 0, 0, death_to, False)
)
death_obj.set_date_object(death_date)
db.commit_event(death_obj, trans)
# Function to synchronize birth dates based on death dates
def syncBirthDates(dates):
death_from = dates['death']['from']
death_to = dates['death']['to']
if dates['birth']['has_exact_date']:
return dates
if death_from:
dates['birth']['from'] = get_larger(dates["birth"]["from"], death_from - 100)
if death_to:
dates['birth']['to'] = get_less(dates["birth"]["to"], death_to)
return dates
# Function to synchronize death dates based on birth dates
def syncDeathDates(dates):
birth_from = dates['birth']['from']
birth_to = dates['birth']['to']
if dates['death']['has_exact_date']:
return dates
if birth_from:
dates['death']['from'] = get_larger(dates["death"]["from"], birth_from)
if birth_to:
dates['death']['to'] = get_less(dates["death"]["to"], birth_to + 100)
return dates
[statements]
# Calculating events for the main person
dates = calcPersonEvents(self)
# Calculating events for each family member and updating the main person's dates
for personFamily in families:
dates = calcPersonFamily(personFamily, dates)
# Calculating events for each spouse and adjusting birth dates
for spouse in spouses:
spouseDates = calcPersonEvents(spouse)
personizedDates = wideDates(spouseDates, -30, 30)
dates = combineBirth(dates, personizedDates)
# Calculating events for each child and adjusting birth dates based on gender
for child in children:
childDates = calcPersonEvents(child)
if gender == "M":
personizedDates = wideDates(childDates, -70, -18)
elif gender == "F":
personizedDates = wideDates(childDates, -55, -16)
else:
personizedDates = wideDates(childDates, -70, -16)
dates = combineBirth(dates, personizedDates)
# Calculating events for the father and adjusting birth dates
if father:
fatherDates = calcPersonEvents(father)
personizedDates = wideDates(fatherDates, 18, 70)
dates = combineBirth(dates, personizedDates)
# Calculating events for the mother and adjusting birth dates
if mother:
motherDates = calcPersonEvents(mother)
personizedDates = wideDates(motherDates, 16, 55)
dates = combineBirth(dates, personizedDates)
# Synchronizing birth and death dates
dates = syncBirthDates(dates)
dates = syncDeathDates(dates)
# Updating birth and death events with the adjusted dates
# You need uncomment two rows below to update the event in the DB
# updateBirthEvent(dates)
# updateDeathEvent(dates)
[filter]
[expressions]
[scope]
all
[unwind_lists]
True
[commit_changes]
False
[summary_only]
False