From a78b7fe67adeb9d35fd72a03f789d2e0f3dd0b00 Mon Sep 17 00:00:00 2001 From: Ommodi07 Date: Thu, 16 Oct 2025 14:30:30 +0530 Subject: [PATCH 1/3] Add algorithm to compute absolute age difference --- maths/age_difference.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 maths/age_difference.py diff --git a/maths/age_difference.py b/maths/age_difference.py new file mode 100644 index 000000000000..66cf11283b64 --- /dev/null +++ b/maths/age_difference.py @@ -0,0 +1,38 @@ +""" +Algorithm to calculate the absolute age difference between two people. + +Wikipedia: https://en.wikipedia.org/wiki/Chronological_age +""" + + +def age_difference(boy_age: int, girl_age: int) -> int: + """ + Return the absolute age difference between two people. + + The function raises a ValueError if any of the ages is negative. + + >>> age_difference(22, 20) + 2 + >>> age_difference(20, 22) + 2 + >>> age_difference(30, 30) + 0 + >>> age_difference(-1, 5) + Traceback (most recent call last): + ... + ValueError: Age cannot be negative. + >>> age_difference(18, -2) + Traceback (most recent call last): + ... + ValueError: Age cannot be negative. + """ + if boy_age < 0 or girl_age < 0: + raise ValueError("Age cannot be negative.") + return abs(boy_age - girl_age) + + +if __name__ == "__main__": + # Example usage (not required by TheAlgorithms, but for local testing) + print(age_difference(22, 20)) # 2 + print(age_difference(20, 22)) # 2 + print(age_difference(30, 30)) # 0 From f0c143a314e5276c2ec042c702c48c6b6bfed893 Mon Sep 17 00:00:00 2001 From: Ommodi07 Date: Sun, 19 Oct 2025 18:36:02 +0530 Subject: [PATCH 2/3] updates age_difference.py --- maths/age_difference.py | 85 ++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 26 deletions(-) diff --git a/maths/age_difference.py b/maths/age_difference.py index 66cf11283b64..1b8077fe664e 100644 --- a/maths/age_difference.py +++ b/maths/age_difference.py @@ -1,38 +1,71 @@ """ -Algorithm to calculate the absolute age difference between two people. +Algorithm to calculate the absolute age difference between two dates (YYYY-MM-DD). Wikipedia: https://en.wikipedia.org/wiki/Chronological_age """ +from __future__ import annotations -def age_difference(boy_age: int, girl_age: int) -> int: - """ - Return the absolute age difference between two people. +from datetime import date - The function raises a ValueError if any of the ages is negative. - >>> age_difference(22, 20) - 2 - >>> age_difference(20, 22) - 2 - >>> age_difference(30, 30) - 0 - >>> age_difference(-1, 5) - Traceback (most recent call last): - ... - ValueError: Age cannot be negative. - >>> age_difference(18, -2) +def parse_date(dob: str) -> date: + """ + Convert a YYYY-MM-DD date string to a `date` object. + + >>> parse_date("2000-01-01") + datetime.date(2000, 1, 1) + >>> parse_date("1999-12-31") + datetime.date(1999, 12, 31) + >>> parse_date("2000-13-01") # Invalid month Traceback (most recent call last): - ... - ValueError: Age cannot be negative. + ... + ValueError: Invalid date format or value: 2000-13-01 + """ + try: + year, month, day = map(int, dob.split("-")) + return date(year, month, day) + except Exception as e: + raise ValueError(f"Invalid date format or value: {dob}") from e + + +def absolute_age_difference(dob1: str, dob2: str) -> tuple[int, int, int]: """ - if boy_age < 0 or girl_age < 0: - raise ValueError("Age cannot be negative.") - return abs(boy_age - girl_age) + Returns the absolute age difference as (years, months, days). + + >>> absolute_age_difference("1990-05-10", "1995-07-15") + (5, 2, 5) + >>> absolute_age_difference("2000-02-29", "2001-02-28") + (0, 11, 30) + >>> absolute_age_difference("2000-01-01", "2000-01-01") + (0, 0, 0) + """ + d1, d2 = parse_date(dob1), parse_date(dob2) + + if d1 == d2: + return (0, 0, 0) + + # Order dates so d1 is always the earlier date + if d1 > d2: + d1, d2 = d2, d1 + + years = d2.year - d1.year + months = d2.month - d1.month + days = d2.day - d1.day + + # Adjust for negative days + if days < 0: + months -= 1 + previous_month = d2.month - 1 or 12 + previous_year = d2.year if d2.month != 1 else d2.year - 1 + days += ( + date(previous_year, previous_month + 1, 1) + - date(previous_year, previous_month, 1) + ).days + # Adjust for negative months + if months < 0: + years -= 1 + months += 12 -if __name__ == "__main__": - # Example usage (not required by TheAlgorithms, but for local testing) - print(age_difference(22, 20)) # 2 - print(age_difference(20, 22)) # 2 - print(age_difference(30, 30)) # 0 + return years, months, days From f58c1b6951fc3741850c68c4672fbc6e4e45feca Mon Sep 17 00:00:00 2001 From: Ommodi07 Date: Sun, 19 Oct 2025 18:51:02 +0530 Subject: [PATCH 3/3] updates age-diff algo --- maths/age_difference.py | 75 ++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/maths/age_difference.py b/maths/age_difference.py index 1b8077fe664e..157b261f0bc4 100644 --- a/maths/age_difference.py +++ b/maths/age_difference.py @@ -1,12 +1,18 @@ +#!/usr/bin/env python3 """ -Algorithm to calculate the absolute age difference between two dates (YYYY-MM-DD). +Age difference calculator. -Wikipedia: https://en.wikipedia.org/wiki/Chronological_age +This module provides functions to compute the absolute age difference between +two birthdates in years, months, and days. + +Doctest usage: + python3 -m doctest -v maths/age_difference.py """ from __future__ import annotations from datetime import date +from typing import Tuple def parse_date(dob: str) -> date: @@ -25,45 +31,60 @@ def parse_date(dob: str) -> date: try: year, month, day = map(int, dob.split("-")) return date(year, month, day) - except Exception as e: - raise ValueError(f"Invalid date format or value: {dob}") from e + except Exception as e: # noqa: BLE001 + msg = f"Invalid date format or value: {dob}" + raise ValueError(msg) from e + +def _days_in_previous_month(ref: date) -> int: + """ + Return the number of days in the month before the given date's month. -def absolute_age_difference(dob1: str, dob2: str) -> tuple[int, int, int]: + >>> _days_in_previous_month(date(2020, 3, 5)) # Feb in leap year + 29 + >>> _days_in_previous_month(date(2021, 3, 5)) # Feb non-leap + 28 """ - Returns the absolute age difference as (years, months, days). + first_of_month = ref.replace(day=1) + previous_month_last_day = first_of_month - date.resolution + return previous_month_last_day.day + + +def absolute_age_difference(d1: str, d2: str) -> Tuple[int, int, int]: + """ + Return the absolute difference between two dates as (years, months, days). + + Rules: + - Order does not matter + - Uses calendar-accurate borrowing of months and days + - Handles leap years + >>> absolute_age_difference("2000-01-01", "2000-01-01") + (0, 0, 0) >>> absolute_age_difference("1990-05-10", "1995-07-15") (5, 2, 5) + >>> absolute_age_difference("1995-07-15", "1990-05-10") + (5, 2, 5) >>> absolute_age_difference("2000-02-29", "2001-02-28") (0, 11, 30) - >>> absolute_age_difference("2000-01-01", "2000-01-01") - (0, 0, 0) """ - d1, d2 = parse_date(dob1), parse_date(dob2) - - if d1 == d2: - return (0, 0, 0) + a = parse_date(d1) + b = parse_date(d2) - # Order dates so d1 is always the earlier date - if d1 > d2: - d1, d2 = d2, d1 + # Ensure a <= b + if a > b: + a, b = b, a - years = d2.year - d1.year - months = d2.month - d1.month - days = d2.day - d1.day + years = b.year - a.year + months = b.month - a.month + days = b.day - a.day - # Adjust for negative days + # Borrow days if needed if days < 0: months -= 1 - previous_month = d2.month - 1 or 12 - previous_year = d2.year if d2.month != 1 else d2.year - 1 - days += ( - date(previous_year, previous_month + 1, 1) - - date(previous_year, previous_month, 1) - ).days - - # Adjust for negative months + days += _days_in_previous_month(b) + + # Borrow months if needed if months < 0: years -= 1 months += 12