From 23c41741707c4416e5d6605cde89895938eb5814 Mon Sep 17 00:00:00 2001 From: The17thDoctor <40616434+The17thDoctor@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:51:44 +0100 Subject: [PATCH 1/5] =?UTF-8?q?C'est=20termin=C3=A9=20(je=20pense)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __main__.py | 12 +++++++- doomsday/algorithm.py | 72 ++++++++++++++++++++++++++++++++++++++++++- doomsday/date.py | 48 +++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) diff --git a/__main__.py b/__main__.py index 53c2c43..b25a3c5 100644 --- a/__main__.py +++ b/__main__.py @@ -1,5 +1,15 @@ +import doomsday.date as date +import doomsday.algorithm as algorithm + + def main() -> None: - print("Hello world") + date_string: str = input("Date (format YYYY-MM-DD): ") + + if (not date.is_valid_date(date_string)): + return + + weekday_at_given_date: str = algorithm.get_weekday_for_date(date_string) + print(f"The date {date_string} is a {weekday_at_given_date}.") main() diff --git a/doomsday/algorithm.py b/doomsday/algorithm.py index cf81d60..ecce641 100644 --- a/doomsday/algorithm.py +++ b/doomsday/algorithm.py @@ -1,2 +1,72 @@ +import math +import doomsday.date as date + +CENTURY_OFFSETS = (2, 0, 5, 3) +DAY_NAMES = ( + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" +) + + +def get_anchor_day_for_year(year: int) -> int: + """Returns the anchor day of a given year starting at 0 for Sunday""" + + # The last two digits of the year in order to apply the Odd + 11 algorithm + year_digits: int = year % 100 + if (year_digits % 2 == 1): + year_digits += 11 + + year_digits = int(year_digits / 2) + if (year_digits % 2 == 1): + year_digits += 11 + + multiple_of_7: int = math.ceil(year_digits / 7) * 7 + # Calculate the century offset for the current year + century_index: int = int(year / 100) % 4 + century_offset = CENTURY_OFFSETS[century_index] + + return multiple_of_7 - year_digits + century_offset + + +def get_anchor_for_month(month: int, year: int) -> int: + """Returns the anchor day of a given month given the year""" + + match (month): + case 4, 6, 8, 10, 12: + return month + case 1: + return 11 if date.is_leap_year(year) else 10 + case 2: + return 22 if date.is_leap_year(year) else 21 + case 3: + return 0 + case 5: + return 9 + case 7: + return 11 + case 9: + return 5 + case 11: + return 7 + + return 0 + + def get_weekday_for_date(date: str) -> str: - return "Sunday" + date_split: list[str] = date.split("-") + year: int = int(date_split[0]) + month: int = int(date_split[1]) + day: int = int(date_split[2]) + + year_anchor_day: int = get_anchor_day_for_year(year) + month_anchor: int = get_anchor_for_month(month, year) + day_offset: int = abs(day - month_anchor) + + final_day_index = (year_anchor_day + day_offset) % 7 + + return DAY_NAMES[final_day_index] diff --git a/doomsday/date.py b/doomsday/date.py index 0f8e737..a629cb8 100644 --- a/doomsday/date.py +++ b/doomsday/date.py @@ -1,2 +1,50 @@ +DAYS_PER_MONTH = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) + + +def get_days_per_month(month: int, year: int) -> int: + """Returns the number of day of the given month, + accounting for leap years""" + + if (month == 2 and is_leap_year(year)): + return DAYS_PER_MONTH[month - 1] + 1 + else: + return DAYS_PER_MONTH[month - 1] + + +def is_leap_year(year: int) -> bool: + """Check if a year is a leap year. + Leap years are every year that are multiples of 4 but not multiples of 100 + or years that are multiple of 400.""" + + return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0 + + def is_valid_date(date: str) -> bool: + + split_date: list[str] = date.split("-") + + # Check for valid number of date components + if (len(split_date) != 3 or "" in split_date): + print("Date must be formatted as YYYY-MM-DD") + return False + + year: int = int(split_date[0]) + month: int = int(split_date[1]) + day: int = int(split_date[2]) + + # Years below 1583 are not supported. + if (year < 1583): + print("For simplicity, years before 1583 are not supported.") + return False + + # Check for valid month + if (month < 1 or month > 12): + print("Invalid month") + return False + + # Check for valid day, accounting for leap years. + if (day < 1 or day > get_days_per_month(month, year)): + print("Invalid day number for the given date.") + return False + return True From 4cf9f1ec654f26288c2070157d24be77932e42a0 Mon Sep 17 00:00:00 2001 From: The17thDoctor <40616434+The17thDoctor@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:35:50 +0100 Subject: [PATCH 2/5] =?UTF-8?q?Petit=20fix=20op=C3=A9rateur=20euclidien?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doomsday/algorithm.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doomsday/algorithm.py b/doomsday/algorithm.py index ecce641..f80d8b2 100644 --- a/doomsday/algorithm.py +++ b/doomsday/algorithm.py @@ -16,18 +16,18 @@ def get_anchor_day_for_year(year: int) -> int: """Returns the anchor day of a given year starting at 0 for Sunday""" - # The last two digits of the year in order to apply the Odd + 11 algorithm + # Apply the Odd + 11 algorithm year_digits: int = year % 100 if (year_digits % 2 == 1): year_digits += 11 - year_digits = int(year_digits / 2) + year_digits = year_digits // 2 if (year_digits % 2 == 1): year_digits += 11 - multiple_of_7: int = math.ceil(year_digits / 7) * 7 # Calculate the century offset for the current year - century_index: int = int(year / 100) % 4 + multiple_of_7: int = math.ceil(year_digits / 7) * 7 + century_index: int = (year // 100) % 4 century_offset = CENTURY_OFFSETS[century_index] return multiple_of_7 - year_digits + century_offset From 6aa0df5b11130d101df994b1ebe400c585b81050 Mon Sep 17 00:00:00 2001 From: The17thDoctor <40616434+The17thDoctor@users.noreply.github.com> Date: Wed, 15 Nov 2023 16:26:35 +0100 Subject: [PATCH 3/5] Fix remarques date.py --- doomsday/date.py | 56 +++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/doomsday/date.py b/doomsday/date.py index a629cb8..ee2129a 100644 --- a/doomsday/date.py +++ b/doomsday/date.py @@ -1,29 +1,15 @@ DAYS_PER_MONTH = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) -def get_days_per_month(month: int, year: int) -> int: - """Returns the number of day of the given month, - accounting for leap years""" - - if (month == 2 and is_leap_year(year)): - return DAYS_PER_MONTH[month - 1] + 1 - else: - return DAYS_PER_MONTH[month - 1] - - -def is_leap_year(year: int) -> bool: - """Check if a year is a leap year. - Leap years are every year that are multiples of 4 but not multiples of 100 - or years that are multiple of 400.""" - - return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0 - - def is_valid_date(date: str) -> bool: + """ + Returns whether a date is properly formatted to the YYYY-MM-DD format and + can be ran through the doomsday algorithm. + """ split_date: list[str] = date.split("-") - # Check for valid number of date components + # Check for correct date format if (len(split_date) != 3 or "" in split_date): print("Date must be formatted as YYYY-MM-DD") return False @@ -32,11 +18,23 @@ def is_valid_date(date: str) -> bool: month: int = int(split_date[1]) day: int = int(split_date[2]) + if (not date_exists(year, month, day)): + return False + # Years below 1583 are not supported. if (year < 1583): print("For simplicity, years before 1583 are not supported.") return False + return True + + +def date_exists(year: int, month: int, day: int) -> bool: + """ + Checks whether the given date can be ran into the doomsday algorithm. + Invalid dates are dates before 1583-01-01. + """ + # Check for valid month if (month < 1 or month > 12): print("Invalid month") @@ -46,5 +44,23 @@ def is_valid_date(date: str) -> bool: if (day < 1 or day > get_days_per_month(month, year)): print("Invalid day number for the given date.") return False - + return True + + +def get_days_per_month(month: int, year: int) -> int: + """Returns the number of day of the given month, + accounting for leap years""" + + if (month == 2 and is_leap_year(year)): + return DAYS_PER_MONTH[month - 1] + 1 + else: + return DAYS_PER_MONTH[month - 1] + + +def is_leap_year(year: int) -> bool: + """Check if a year is a leap year. + Leap years are every year that are multiples of 4 but not multiples of 100 + or years that are multiple of 400.""" + + return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0 From e3cc654034b2112bec83e7fcc4c40b1103027767 Mon Sep 17 00:00:00 2001 From: The17thDoctor <40616434+The17thDoctor@users.noreply.github.com> Date: Wed, 15 Nov 2023 16:40:44 +0100 Subject: [PATCH 4/5] Fix commentaires algorithm.py --- doomsday/algorithm.py | 60 +++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/doomsday/algorithm.py b/doomsday/algorithm.py index f80d8b2..ab54715 100644 --- a/doomsday/algorithm.py +++ b/doomsday/algorithm.py @@ -13,6 +13,27 @@ ) +def get_weekday_for_date(date: str) -> str: + """Returns the name of the day at a given date.""" + date_split: list[str] = date.split("-") + year: int = int(date_split[0]) + month: int = int(date_split[1]) + day: int = int(date_split[2]) + + year_anchor_day: int = get_anchor_day_for_year(year) + month_anchor: int = get_anchor_for_month(month, year) + + # Calculate the number of days between the month's anchor day and + # the wanted day. + day_offset: int = abs(day - month_anchor) + # Since the month's anchor day and the year's anchor day are the same + # we can add the year's anchor day index to get the final day index. + final_day_index = (year_anchor_day + day_offset) % 7 + + return DAY_NAMES[final_day_index] + + + def get_anchor_day_for_year(year: int) -> int: """Returns the anchor day of a given year starting at 0 for Sunday""" @@ -36,37 +57,10 @@ def get_anchor_day_for_year(year: int) -> int: def get_anchor_for_month(month: int, year: int) -> int: """Returns the anchor day of a given month given the year""" - match (month): - case 4, 6, 8, 10, 12: - return month - case 1: - return 11 if date.is_leap_year(year) else 10 - case 2: - return 22 if date.is_leap_year(year) else 21 - case 3: - return 0 - case 5: - return 9 - case 7: - return 11 - case 9: - return 5 - case 11: - return 7 - - return 0 - - -def get_weekday_for_date(date: str) -> str: - date_split: list[str] = date.split("-") - year: int = int(date_split[0]) - month: int = int(date_split[1]) - day: int = int(date_split[2]) + month_anchors = ( + 11 if date.is_leap_year(year) else 10, + 22 if date.is_leap_year(year) else 21, + 0, 4, 9, 6, 11, 8, 7, 10, 7, 12 + ) - year_anchor_day: int = get_anchor_day_for_year(year) - month_anchor: int = get_anchor_for_month(month, year) - day_offset: int = abs(day - month_anchor) - - final_day_index = (year_anchor_day + day_offset) % 7 - - return DAY_NAMES[final_day_index] + return month_anchors[month - 1] From a6f0c0cbf61ad54c731c9e65c244ea53b80dd0af Mon Sep 17 00:00:00 2001 From: The17thDoctor <40616434+The17thDoctor@users.noreply.github.com> Date: Wed, 15 Nov 2023 16:46:40 +0100 Subject: [PATCH 5/5] =?UTF-8?q?Oups,=20j'ai=20oubli=C3=A9=20de=20pycodetes?= =?UTF-8?q?t.exe=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doomsday/algorithm.py | 1 - doomsday/date.py | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/doomsday/algorithm.py b/doomsday/algorithm.py index ab54715..d3ad35b 100644 --- a/doomsday/algorithm.py +++ b/doomsday/algorithm.py @@ -33,7 +33,6 @@ def get_weekday_for_date(date: str) -> str: return DAY_NAMES[final_day_index] - def get_anchor_day_for_year(year: int) -> int: """Returns the anchor day of a given year starting at 0 for Sunday""" diff --git a/doomsday/date.py b/doomsday/date.py index ee2129a..f90d907 100644 --- a/doomsday/date.py +++ b/doomsday/date.py @@ -20,7 +20,7 @@ def is_valid_date(date: str) -> bool: if (not date_exists(year, month, day)): return False - + # Years below 1583 are not supported. if (year < 1583): print("For simplicity, years before 1583 are not supported.") @@ -34,7 +34,7 @@ def date_exists(year: int, month: int, day: int) -> bool: Checks whether the given date can be ran into the doomsday algorithm. Invalid dates are dates before 1583-01-01. """ - + # Check for valid month if (month < 1 or month > 12): print("Invalid month") @@ -44,7 +44,7 @@ def date_exists(year: int, month: int, day: int) -> bool: if (day < 1 or day > get_days_per_month(month, year)): print("Invalid day number for the given date.") return False - + return True