Skip to main content
fixed link
Source Link
Ben A
  • 10.8k
  • 5
  • 40
  • 103

Instead of calculating a leap year yourself, you can use calendar.isleap from the [calendar][1]calendar module.

This line unpacks each item from the tuple returned by get_date_values and passes them to the function. Since the tuple has three values, and check_date accepts three parameters, the * unpacks the tuple and passes each value to the function. [1]: https://docs.python.org/3/library/calendar.html

Instead of calculating a leap year yourself, you can use calendar.isleap from the [calendar][1] module.

This line unpacks each item from the tuple returned by get_date_values and passes them to the function. Since the tuple has three values, and check_date accepts three parameters, the * unpacks the tuple and passes each value to the function. [1]: https://docs.python.org/3/library/calendar.html

Instead of calculating a leap year yourself, you can use calendar.isleap from the calendar module.

This line unpacks each item from the tuple returned by get_date_values and passes them to the function. Since the tuple has three values, and check_date accepts three parameters, the * unpacks the tuple and passes each value to the function.

Source Link
Ben A
  • 10.8k
  • 5
  • 40
  • 103

Docstrings / Type hints

These allow you to describe how your code works in a pythonic manner. Docstrings allow IDE's and other documentation tools to see what your function/class does. Type hints allow you to show what types of parameters are accepted, and what types of values are returned.

check_date

Instead of calculating a leap year yourself, you can use calendar.isleap from the [calendar][1] module.

Return comparisons, not raw booleans

Instead of

if day <= day_bound:
    return True
return False

do this

return day <= day_bound

Does the exact same thing, but looks a lot nicer.

Split code into functions

You've done a good job splitting your code into functions, but I think you could use one more. Instead of parsing the date in the "main" code, put that code in another function, and pass it the date string.

def get_date_values(...) -> ...:
   ...

With all these changes, your final code would look something like this:

import re
import calendar
from typing import Tuple, Union

def check_date(day: int, month: int, year: int) -> bool:
    """
    Returns a bool based on if the date passed is a valid date.

    :param int day: Day.
    :param int month: Month.
    :param int year: Year.

    :return: True if a valid date, False otherwise.
    """
    # April, June, September, November = 30 days/ February = 28 days, unless leapyear so 29/ rest has 31 days
    month_dict = {4: 30, 6: 30, 9: 30, 11: 30, 2: 28}
    day_bound = month_dict.get(month, 31)

    if day_bound == 28:
        if calendar.isleap(year):
            day_bound = 29

    return day <= day_bound


def get_date_values(date: str) -> Union[Tuple[int, int, int], None]:
    """
    Returns a tuple containing the day, month, and year of the passed date.

    :param str date: Date to parse and retrieve values.

    :return: Either a Tuple, or for an invalid date, None.
    """
    date_regex = re.compile(r"([0-2]\d|3[01])/(0\d|1[0-2])/([12]\d{3})")
    match = date_regex.search(date)
    if match:
        return (int(match.group(1)), int(match.group(2)), int(match.group(3)))
    return None


if __name__ == "__main__":
    date = "31/02/2020" #DD/MM/YYYY
    if check_date(*get_date_values(date)):
        print('Valid Date!')
    else:
        print('Invalid Date!')

I'll explain a bit more since I made some changes I haven't mentioned already.

Unpacking

if check_date(*get_date_values(date)):

This line unpacks each item from the tuple returned by get_date_values and passes them to the function. Since the tuple has three values, and check_date accepts three parameters, the * unpacks the tuple and passes each value to the function. [1]: https://docs.python.org/3/library/calendar.html