diff --git a/__main__.py b/__main__.py index 53c2c43..8697d33 100644 --- a/__main__.py +++ b/__main__.py @@ -1,5 +1,18 @@ +from doomsday.date import is_valid_date +from doomsday.algorithm import get_weekday_for_date + + def main() -> None: - print("Hello world") + """Programme principal""" + print("- Doomsday algorithm -") + + while True: + date: str = input("Enter a date (expected format : ) : ") + if is_valid_date(date): + print(get_weekday_for_date(date)) + try_again: str = input("Try another date ? (y/n) : ").lower().strip() + if try_again != "y": + break main() diff --git a/doomsday/algorithm.py b/doomsday/algorithm.py index cf81d60..9e920d5 100644 --- a/doomsday/algorithm.py +++ b/doomsday/algorithm.py @@ -1,2 +1,67 @@ +from doomsday.date import is_leap_year + + +DAYS_OF_WEEK = ( + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday' + ) + +PIVOT_DAY_LEAP = (4, 1) + +PIVOT_DAY = (3, 0, 0, 4, 2, 6, 4, 1, 5, 3, 0, 5) + + def get_weekday_for_date(date: str) -> str: - return "Sunday" + """ + Détermine le jour du jugement dernier à partir d'une date donnée + Format attendu : YYYY-MM-dd + """ + + date_in_list: list[str] = date.split("-") + + year: int = int(date_in_list[0]) + month: int = int(date_in_list[1]) + day: int = int(date_in_list[2]) + + # 1re partie : déterminer le jour "ancre" de l'année + + anchor_day: int = get_anchor_day(year) + + # 2e partie : déterminer un jour particulier en fonction du jour ancre + + if is_leap_year(year) and (month == 1 or month == 2): + return DAYS_OF_WEEK[(day - PIVOT_DAY[month - 1] + anchor_day) % 7] + else: + return DAYS_OF_WEEK[(day - PIVOT_DAY[month - 1] + anchor_day) % 7] + + +def get_anchor_day(year: int) -> int: + """Détermine le jour 'ancre' d'une année""" + + year_end: int = year % 100 # La fin de l'année + century: int = int(year / 100) # Le siècle + century_value: int = 0 # Le décalage lié au siècle + + # Si fin d'année pair /2, sinon +11 et /2 puis si toujours impair +11 + if year_end % 2 != 0: + year_end += 11 + year_end //= 2 + if year_end % 2 != 0: + year_end += 11 + + # Obtenir le multiple de 7 supérieur ou égal + multiple_of_7: int = int(year_end) + if (multiple_of_7 % 7) != 0: + multiple_of_7 += 7 - multiple_of_7 % 7 + + # Obtenir le décalage du siècle + century_values = [2, 0, 5, 3] + + century_value = century_values[century % 4] + + return multiple_of_7 - int(year_end) + century_value diff --git a/doomsday/date.py b/doomsday/date.py index 0f8e737..a8373c0 100644 --- a/doomsday/date.py +++ b/doomsday/date.py @@ -1,2 +1,94 @@ def is_valid_date(date: str) -> bool: + """ + Retourne 'vrai' si la date est valide + Format attendu : "YYYY-MM-dd" + Exeptions : - jour : 1 caractère accepté + - mois : 1 caractère accepté + - année : 4+ caractères acceptés + Date minimale : 1583-01-01 + Affiche une explication si erreur + """ + + date_in_list: list[str] = date.split("-") + + # Vérifier que la chaîne en paramètre est de format str-str-str + if len(date_in_list) != 3: + print("Please use format YYYY-MM-dd") + return False + + year: str = date_in_list[0] + month: str = date_in_list[1] + day: str = date_in_list[2] + + # Si le l'année, le mois et le jour sont valides, retourne Vrai + return is_valid_year(year) and is_valid_month(month) and \ + is_valid_day(day, month, year) + + +def is_valid_year(year: str) -> bool: + """ Retourne 'vrai' si l'année est valide""" + # Vérifier que l'année soit composée de chiffres + if not year.isnumeric(): + print("Year is not numeric format") + return False + + # Vérifier que l'année soit postérieure à 1583 + if int(year) < 1583: + print("Year must begin after 1583") + return False + return True + + +def is_valid_month(month: str) -> bool: + """ Retourne 'vrai' si le mois est valide""" + # Vérifier que le mois soit composé de chiffres + if not month.isnumeric(): + print("Year is not numeric format") + return False + + # Vérifier si le nombre de caractère est bon (voir ci-haut) + # if len(month) < 1 or len(month) > 2: + # print("Month must have 1 or 2 characters") + # return False + + # Vérifier si le mois existe + if int(month) < 1 and int(month) > 12: + print("Month must be between 1 (january) and 12 (december)") + return False + + return True + + +def is_valid_day(day: str, month: str, year: str) -> bool: + """ Retourne 'vrai' si le jour est valide""" + # Vérifier que le jour soit composé de chiffres + if not day.isnumeric(): + print("Day is not numeric format") + return False + + # Vérifier si le nombre de caractère est bon (voir ci-haut) + if len(day) < 1 or len(day) > 2: + print("Day must have 1 or 2 characters") + return False + + # Vérifier que le jour existe + if int(month) == 2 and is_leap_year(int(year)) and int(day) > 29: + print("Day must be between 1 and 29") + return False + if int(month) == 2 and not is_leap_year(int(year)) and int(day) > 28: + print("Day must be between 1 and 28") + return False + if int(month) % 2 == 1 and int(day) > 31: + print("Day must be between 1 and 31") + return False + if int(month) % 2 == 0 and int(day) > 30: + print("Day must be between 1 and 30") + return False + + return True + + +def is_leap_year(year: int) -> bool: + """Renvoie 'vrai' si l'année en paramètre est bissextile""" + return (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0)