|
| 1 | +"""Utility functions for GEDCOM 7 processing.""" |
| 2 | + |
| 3 | +import datetime |
| 4 | + |
| 5 | +from . import const, types |
| 6 | + |
| 7 | + |
| 8 | +def get_first_child_with_tag( |
| 9 | + structure: types.GedcomStructure, tag: str |
| 10 | +) -> types.GedcomStructure | None: |
| 11 | + """Get the first child of a GEDCOM structure with a specific tag. |
| 12 | +
|
| 13 | + If no child with the specified tag is found, return None. |
| 14 | + """ |
| 15 | + for child in structure.children: |
| 16 | + if child.tag == tag: |
| 17 | + return child |
| 18 | + return None |
| 19 | + |
| 20 | + |
| 21 | +def date_exact_to_python_date(date: types.DateExact) -> datetime.date: |
| 22 | + """Convert a GEDCOM DateExact to a Python date.""" |
| 23 | + try: |
| 24 | + month = const.GEDCOM_MONTHS[date.month.upper()] |
| 25 | + except KeyError: |
| 26 | + raise ValueError(f"Invalid month in date: {date.month}") |
| 27 | + return datetime.date(year=date.year, month=month, day=date.day) |
| 28 | + |
| 29 | + |
| 30 | +def time_to_python_time(time: types.Time) -> datetime.time: |
| 31 | + """Convert a GEDCOM Time to a Python time.""" |
| 32 | + second = 0 |
| 33 | + microsecond = 0 |
| 34 | + if time.second: |
| 35 | + second = time.second |
| 36 | + if time.fraction: |
| 37 | + fraction = float(f"0.{time.fraction}") |
| 38 | + microsecond = int(fraction * 1_000_000) |
| 39 | + return datetime.time( |
| 40 | + hour=time.hour, |
| 41 | + minute=time.minute, |
| 42 | + second=second, |
| 43 | + microsecond=microsecond, |
| 44 | + tzinfo=datetime.timezone.utc, |
| 45 | + ) |
| 46 | + |
| 47 | + |
| 48 | +def date_exact_and_time_to_python_datetime( |
| 49 | + date: types.DateExact, time: types.Time | None = None |
| 50 | +) -> datetime.datetime: |
| 51 | + """Convert a GEDCOM date and optional time to a Python datetime.""" |
| 52 | + date_obj = date_exact_to_python_date(date) |
| 53 | + if time: |
| 54 | + time_obj = time_to_python_time(time) |
| 55 | + return datetime.datetime.combine(date_obj, time_obj) |
| 56 | + return datetime.datetime.combine( |
| 57 | + date_obj, datetime.time.min, tzinfo=datetime.timezone.utc |
| 58 | + ) |
0 commit comments