Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

python class: from goody import irange, type_as_str class Date: month_dict = {1:

ID: 3602514 • Letter: P

Question

python class:

from goody import irange, type_as_str

class Date:
month_dict = {1:31, 2:28, 3:31, 4:30, 5:31, 6:30, 7:31, 8:31, 9:30, 10:31, 11:30, 12:31}

@staticmethod
def is_leap_year(year):
return (year%4 == 0 and year%100 != 0) or year%400 == 0
  
@staticmethod
def days_in(year,month):
return Date.month_dict[month] + (1 if month == 2 and Date.is_leap_year(year) else 0)

1. (20 pts) Complete the class Date, which stores and manipulates dates. As specified below, write the required methods, including those needed for overloading operators. Exceptions messages should include the class and method names, and identify the error (including the value of all relevant arguments). Hint see the type as str function in the goody.py module. You may not import/use the datetime or other similar modules in Python. I. The class is initialized with three int values (the year first, the month second, the day third.) If any parameter is not an int, or not in the correct range (the year must be 0 or greater, the month must be between 1 and 12 inclusive, and the day must be legal given the month and year: remember about leap years) raise an AssertionError with an appropriate string describing the problem/values. When initialized, the Date class should create exactly three self variables named year, month, and day (with these exact names and no others self variables) 2. Write the_getitem_method to allow Date class objects to be indexed by either (a) an str with value 'y' or 'm' or 'd', or (b) any length tuple containing any combinations of just these three values: e.g., ('m', 'd'). If the index is not one of these types or values, raise an IndexError exception with an appropriate string describing the problem/values. If the argument is 'y' returns the year; if the argument is 'm', return the month, and if the argument is 'd', return the day. If the argument is a tuple, return a tuple with year or month or day substituted for each value in the tuple. So ifd - day (2016,4,15) then d['y'] returns 2016 and dl'm', 'd'] returns (4,15). Note that calling dl'm'] will pass 'm' as its argument, calling t['m', 'd'] will pass the tuple ('m', 'd') as its argument. 3. Write methods that return (a) the standard repr function of a Date, and (b) a str function of a Date: str for a Date shows the date in the standard format: str (Date (2016,4,15)) returns '4/15/2016'; it is critical to write the str method correctly, because I used it in the batch self-check file for testing the correctness of other methods. 4. Write a method that interprets the length of a Date as the number of days that have elapsed from January 15 in the year 0 to that date. So len (Date (0,1,1)) returns 0; len (Date (0,12,31)) returns 365; len (Date (2016,4,15)) returns 736,434. Hint: len (Date(0,3,14)) returns 73: 30 days in January, 29 days in February (it is a leap month), and 14 days in March, which sum to 73.

Explanation / Answer

from goody import irange, type_as_str
from calendar import month


class Date:
    month_dict = {1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31}

    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

        assert type(self.month) == int and type(self.year) == int and type(self.day) == int, 'Typer Error, ' + str(
            self.month) + ' and ' + str(self.year) + ' and ' + str(self.day) + ' must all be integers'
        assert self.year >= 0 and self.month in range(1, 13), str(self.year) + ' must be greater than 0'
        assert self.days_in(self.year, self.month) >= self.day, str(self.month) + ' does not have ' + str(
            self.day) + ' days'

    def __getitem__(self, *args):
        alist = []
        for arg in args:
            if arg == 'y':
                return self.year
            elif arg == 'm':
                return self.month
            elif arg == 'd':
                return self.day
            elif type(arg) == tuple:
                for arg in args:
                    for the_arg in arg:
                        if the_arg == 'y':
                            alist.append(self.year)
                        elif the_arg == 'm':
                            alist.append(self.month)
                        elif the_arg == 'd':
                            alist.append(self.day)
            else:
                raise IndexError
        return tuple(alist)

    def __str__(self):
        astring = str(self.month) + '/' + str(self.day) + '/' + str(self.year)
        return astring

    def __repr__(self):
        astring = 'Date(' + str(self.year) + ',' + str(self.month) + ',' + str(self.day) + ')'
        return astring

    def __len__(self):

        days = 0
        for year in range(self.year):
            days += 366 if self.is_leap_year(year) else 365
        for month in range(1, self.month):
            days += self.days_in(self.year, month)
        days += self.day - 1
        return days

    #         for year in range(0, self.year):
    #
    #             for current_month in range(1, 13):
    #                 days += self.days_in(year,current_month)
    #
    #         for current_month in range(1, self.month):
    #             days += self.days_in(self.year, current_month)
    #         days += self.day
    #         return days - 1


    def __eq__(self, right):
        if type(self) != type(right):
            return False

        elif self.year == right.year and self.month == right.month and self.day == right.day:
            return True

        else:
            return False

    def __lt__(self, right):
        if type(right) != int and type(right) != type(self):
            raise TypeError

        if type(self) == type(right):
            return self.__len__() < right.__len__()

        elif type(right) == int:
            return self.__len__() < right

    def __add__(self, right):
        if type(right) is not int:
            raise TypeError(' unsupported operand type(s) for +: ' + type_as_str(self) + ' and ' + type_as_str(right))
        year, month, day = self['y', 'm', 'd']
        for _i in range(abs(right)):
            if right >= 0:
                day += 1
                if day == self.days_in(year, month) + 1:
                    day, month = 1, month + 1
                    if month == 13:
                        month, year = 1, year + 1
            else:
                day -= 1
                if day == 0:
                    month -= 1
                    if month == 0:
                        day, month, year = 31, 12, year - 1
                    else:
                        day = Date.days_in(year, month)
        return Date(year, month, day)

        #         if type(right) != int:
        #             raise TypeError
        #
        #         if right > 0:
        #             while right != 0:
        #
        #                 self.day = self.day + 1
        #                 if self.days_in(self.year, self.month) == self.day:
        #                     self.month += 1
        #                     self.day = 0
        #
        #
        #                 elif self.month == 12 and self.day == 31:
        #                     self.year += 1
        #                     print(self.year)
        #                     self.month = 1
        #                     self.day = 0
        #                     right -= 1
        #                 right -= 1


        return self.__str__()

    def __sub__(self, right):
        if type(self) == type(right):
            new_date = self.__len__() - right.__len__()
            return new_date

        if type(right) == int:
            new_date = self + -right
            return new_date

    def __call__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

        assert type(self.month) == int and type(self.year) == int and type(self.day) == int, 'Typer Error, ' + str(
            self.month) + ' and ' + str(self.year) + ' and ' + str(self.day) + ' must all be integers'
        assert self.year >= 0 and self.month in range(1, 13), str(self.year) + ' must be greater than 0'
        assert self.days_in(self.year, self.month) >= self.day, str(self.month) + ' does not have ' + str(
            self.day) + ' days'

    @staticmethod
    def is_leap_year(year):
        return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0

    @staticmethod
    def days_in(year, month):
        return Date.month_dict[month] + (1 if month == 2 and Date.is_leap_year(year) else 0)


if __name__ == '__main__':
    # Put in simple tests for Date before allowing driver to run
    #     a = Date(16, 4, 21)
    #     print(a + 1000)
    print()
    import driver

    driver.default_file_name = 'bsc1.txt'
    #     driver.default_show_traceback = True
    #     driver.default_show_exception = True
    #     driver.default_show_exception_message = True
    driver.driver()