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

Functions Details of function definitions in alphabetical order: - calcExcelDate

ID: 3848608 • Letter: F

Question

Functions

Details of function definitions in alphabetical order:

- calcExcelDate(year, month): This function calculates the current date in the way that Microsoft Excel does; the number of days since the hypothetical date January 0, 1900. This function has been completely done for you (in previous years, this single function was a third of an assignment by itself). If you are curious as to the equations used and the comments don’t answer your questions, please ask your professor. The function returns an integer because it assumes no partial days. o This function is called by listMonthDays and daysInMonth and does not call any user-defined functions

- calcWeekDay(excelDate): Given an integer Excel date (such as what calcExcelDate returns), this function returns an int from 0 to 6 according to what day of the week it is, where 0 is Sunday and 6 is Saturday. Note: if you just take the date % 7, you will get a number from 0 to 6 but it won’t be quite right. It requires a slightly more complicated pattern. o This function is called by listMonthDays and does not call any user-defined functions

- daysInMonth(year, month): The number of days in the given month is the difference between the Excel date of the first day of the month and the Excel date of the first day of the next month. Return this integer. Do not store (i.e. hardcode) the number of days in each month, since the number varies from year to year (at least for February). o This function is called by listMonthDays and calls calcExcelDate

- formatCalendar(monthDetail): The parameter monthDetail is the tuple generated by listMonthDays for a single month. The month name is the first position of the tuple, and the second position is a list of 42 fields to appear in the calendar. Return a single character string that provides the multi-line calendar needed for a single month. Put a newline character at the end of each line. The dark border comes from the Unicode characters provided at the start of A2Q1Skeleton.py o This function is called by main and does not call any user-defined functions

- listMonthDays(year): This function returns monthDetails, a list of 13 items. o The first item, in position 0, is the year that was given to it. The remaining 12 items are the details of the months 1 through 12 for that year. For each month, the details should be stored as a 2-item tuple. The first item in the tuple is the full name (e.g. January) of the month. The second item in the tuple is a list of strings (either 3 characters long or empty) showing what is to be printed in the 42 positions of the monthly calendar (6 weeks * 7 days per week). For example, the details for the month of January in 2015 would be this tuple:

o The month names should come from a constant tuple or list (provided)

o You can calculate the number of blank entries to start each list by calling calcWeekDay with the excelDate of the first day of the month, obtained by calling calcExcelDate. The function calcWeekDay returns a number from 0 to 6 representing Sunday through Saturday. If you know the first day of the month is on a Monday (day 1), then there will be 1 blank day before it. Make sure to add enough blank days at the end of the month to make the total length of the list 42.

o In January and July, replace ‘1’ with '1'. The star character is obtained with a Unicode string. Download UnicodeNames.py from the course website and run it to help you find out what the Unicode string is for the star. The code for a different star is provided in A2Q1Skeleton.py. Make sure you change it!

('JANUARY', ['','','','','1',' 2',' 3',' 4',' 5',' 6',' 7',' 8',' 9',' 10',' 11',' 12',' 13',' 14',' 15',' 16',' 17',' 18',' 19',' 20',' 21',' 22',' 23',' 24',' 25',' 26',' 27',' 28',' 29',' 30',' 31','','','','','','',''])

o This function is called by main and calls calcWeekDay, daysInMonth, and calcExcelDate

- main(): This function takes no parameters. It gets a valid year from the user by calling getIntV2 (getIntV2 is not listed here: it is copied directly from the Week 6 course notes). It then gives that year to listMonthDays, getting back monthDetails. It then prints the calendar months by calling formatCalendar on every individual month. All your print statements should be in this function. o This function is called directly by your script file and calls getIntV2, listMonthDays, and formatCalendar

- theEnd(): This function takes no parameters. It prints the termination output shown at the end of the sample output. You can copy this directly from your Assignment 1 if you feel like you got it right there. o This function is called by main and does not call any user-defined functions

code skeleton:

PURPOSE: To print a calendar for a given year.
"""
from time import ctime
import math

"""Instructions:
- As with Assignment 1, anytime you see GARBAGE, replace it
- Look for # comments followed by TODO, they tell you what to add or change
"""

GARBAGE = 0
UPPER_LEFT = "N{BOX DRAWINGS HEAVY DOWN AND RIGHT}" #Top-left corner
BOTTOM_LEFT = "N{BOX DRAWINGS HEAVY UP AND RIGHT}" #Bottom-left corner
HORIZONTAL = "N{BOX DRAWINGS HEAVY HORIZONTAL}" #Horizontal line
UPPER_RIGHT = "N{BOX DRAWINGS HEAVY DOWN AND LEFT}" #Top-right corner
BOTTOM_RIGHT ="N{BOX DRAWINGS HEAVY UP AND LEFT}" #Bottom-right corner
VERTICAL    = "N{BOX DRAWINGS HEAVY VERTICAL}" #vertical line
BLACK_STAR = "N{STAR OPERATOR}" #Star symbol for holidays
#TODO: Change the Unicode string for BLACK_STAR to the right one

#These are provided for your use. They may come in handy
MONTH_WIDTH = 35 #5*7 --> 3+2 padding for each day of the week
YEAR_WIDTH = (MONTH_WIDTH)*3 + 8 #accounts for padding

#******************************************************************calcExcelDate
def calcExcelDate(year, month, day = 1) :
    """Calculate Excel date for a given year (1900 to 9999), month (1 to 12)
    and day (1 to 31). THIS FUNCTION IS COMPLETE AND CORRECT. DO NOT TOUCH"""
    assertString = "{0} {1} is out of range {2} to {3}" #String for asserts
    assert 1900 <= year < 10000, assertString.format("year",year,1900,9999)
    assert 1 <= month < 13, assertString.format("month",month,1,12)
    assert 1 <= day < 32, assertString.format("day",day,1,31)
    yearAfter1900 = year - 1900 #relative year
    emEarlyMonth = (14 - month) // 12 #We treat early months different
    yearAdj    = yearAfter1900 - emEarlyMonth #Adjusted year
    monthAdj   = month + 12 * emEarlyMonth # count the number of leap years
    leapYears   = ( 1 + min(yearAdj,0) + yearAdj // 4
                  - yearAdj // 100 + (yearAdj + 300) // 400 ) #Leap year calc
    daysToMonth = math.floor(-1.63 + (monthAdj - 1) * 30.6) # adjust for month
    excelDate = day + yearAdj * 365 + leapYears + daysToMonth #final Excel date
    return int(excelDate)

#********************************************************************calcWeekDay
def calcWeekDay(excelDate) :
    """Find the day of the week (0 to 6) for a given Excel Date"""
    return GARBAGE

#********************************************************************daysInMonth
def daysInMonth(year, month) :
    """Purpose: to calculate the number of days in a given month
    parameter: year between 1900 and 9999
    parameter: month from 1 to 12
    return number of days (e.g., 31 for month 1, 28 or 29 for month 2
        depending on the year, ...)"""
    #TODO: figure out the next month to calculate the month length
    #Hint: you might have to handle December specially   
    return GARBAGE

#*****************************************************************formatCalendar
def formatCalendar(monthDetail) :
    """Purpose: to return a string for a calendar for a specific year and
    month where monthDetail is a tuple containing the month name and a list
    of 42 3-character days.
    return: a string containing a month's calendar"""
    name, dates = monthDetail      # month name, list of dates + blanks
    calendar = ""
   
    #TODO: Write this function
    #Hint: This function can be built in three stages
    #Stage 1 is the top part of the month; the top line, name, and day names
    #Stage 2 is the actual dates, which you want a loop for
    #Stage 3 is the end of the month
   
    #Hint 2: You may find the following line useful near the end
    #Especially if you can't get things to line up right when you print
    #calendar = calendar[:-1]

    return calendar


#******************************************************************listMonthDays
def listMonthDays(year) :
    """Purpose: to return a list of 13 entries, the first of which has the
    year. The next 12 entries give details for the 12 months. The entry
    for each month consists of a tuple containing two things: the name of
    the month, and a list of 42 dates to print. Each date consists of a
    3-character field. It would be an empty string for not a valid date,
    and the day as a string for days that will appear on the
    calendar. Two days, New Year's Day and Canada Day should have a dark
    star that is two characters wide, to mark a holiday."""

    MONTHS = ('', "JANUARY",   "FEBRUARY", "MARCH",    "APRIL",
                  "MAY",       "JUNE",     "JULY",     "AUGUST",
                  "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER") #Months
    returnVals = list(range(13))    # return a 13 position list, to be filled
    returnVals[0] = GARBAGE
    for month in range(1,13) :
        excelDate = calcExcelDate(year, month) # excel date for first day
        #TODO: Fill in the rest of this loop
       
    # New Years Day
    #TODO: Find New Years and give it a star
    # Canada Day
    #TODO: Find Canada Day and give it a star
    return returnVals

#*************************************************************************theEnd
def theEnd() :
    """Purpose: to print a final message identifying the programmer,
    giving the date, and saying the program has finished."""
    #TODO: Change to your name
    print ( " Programmed by The Instructors" )
    print ( "Date: " + ctime() )
    print ( "** End of processing **" )


def getIntV2(lo, hi, prompt):
    """Input an integer in range [lo, hi]
    loop until a valid integer is entered
    Use exception handling to deal with non-integers
    THIS FUNCTION IS COMPLETE AND CORRECT
    """
    MSG = " between {0:d} and {1:d}: ".format(lo, hi) #Display message
    warning = "" # backspace; no effect here
    while len(warning) > 0 :
        # warning: what was wrong last time
        userText = input(warning + prompt + MSG)
        warning = ""
        try:
            value = int(userText) #Attempt to convert to int
            if not(lo <= value <= hi):
                warning += ("'" + userText +
                "' is not" + MSG + ' ')
        except ValueError:
            warning += ("'" + userText + "' is not an int ")
    return value

#********************************************the instructions to make a calendar
def main():
    """Purpose: to generate and print a calendar. Calls getIntV2 to get
    the desired year from the user. Prints the year as a header and then
    gets the strings for each month from listMonthDays before printing them
    in a 4x3 block after formatting with calls to formatCalendar"""
   
    #TODO: Write this function
    #You'll need a loop of some kind
    #And the only print statements in your whole program should be here
   
    theEnd( )

main()

Explanation / Answer

#imports
import time
import math

def calcExcelDate(year, month) :
    """Return the Excel Date for any year between 1900 to 9999."""
    day = 1
    y2 = year - 1900
    em = math.floor((14 - month)/12)
    y3 = y2 - em
    m2 = month + 12 * em
    l_ = (1 + min(y3, 0) + math.floor(y3/4) - math.floor(y3/100) +
        math.floor((y3 + 300)/400))
    d1 = math.floor(-1.63 + (m2 - 1) * 30.6)
    d2 = day + y3 * 365 + l_ + d1
    excelDate = int(d2)
    return excelDate

def calcWeekDay(excelDate) :
    """Returns an int from 0 to 6 indicating which day of the week the Excel
    date refers to, where 0 designates Sunday, and 6 designates Saturday"""
    dayInWeek = (excelDate + 6) % 7 #since the day is assumed to be 1 we must
                                        #accomodate for this by adding 6.
    return dayInWeek

def daysInMonth(year, month) :
    """Returns the number of days in a given month using Excel dates."""
    numDays = calcExcelDate(year, month + 1) - calcExcelDate(year, month)
    return numDays

def formatCalendar(monthDetail) :
    """Return a calendar layout for one month."""
    VERTICAL = U"N{BOX DRAWINGS HEAVY VERTICAL}" #unicode for vertical line
    TOP_LEFT = U"N{BOX DRAWINGS HEAVY DOWN AND RIGHT}"
    HORIZONTAL = U"N{BOX DRAWINGS HEAVY HORIZONTAL}"
    TOP_RIGHT = U"N{BOX DRAWINGS HEAVY DOWN AND LEFT}"
    BOTTOM_LEFT = U"N{BOX DRAWINGS HEAVY UP AND RIGHT}"
    BOTTOM_RIGHT = U"N{BOX DRAWINGS HEAVY UP AND LEFT}"
    NEW = ' '
      
    DAYS = ' Sun Mon Tue Wed Thu Fri Sat '
    TOP = TOP_LEFT + HORIZONTAL * 18 + TOP_RIGHT
    BOTTOM = BOTTOM_LEFT + HORIZONTAL * 18 + BOTTOM_RIGHT
           
    month = monthDetail[0] #name of month
    days = monthDetail[1] #list of days in a specific month
    stringOfDays = VERTICAL + " "
  
    for num in range(42) :
        BLANK = " "
        stringOfDays += "%s" % days[num] + BLANK * 2 #converts list to string
      
        if(num > 0 and num % 7 == 6) :
        #starts a new row every seven entries
            stringOfDays += VERTICAL + NEW + (VERTICAL + BLANK) * (num < 41)
          
    formattedMonth = (TOP + NEW + VERTICAL + " %-35s" % month + VERTICAL + NEW
                    + VERTICAL + DAYS + VERTICAL + NEW + stringOfDays + BOTTOM)
    
    return formattedMonth
  
def listMonthDays(year) :
    """Return a list of data for each month."""
    MONTHS = (' ', 'JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE',
              'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER')
    STAR = U"N{BLACK STAR}"
    monthDetails = range(13) #list with 12 items
    monthDetails[0] = year
    for month in range(1, 13) :
        excelDate = calcExcelDate(year, month)
        dayInWeek = calcWeekDay(excelDate)
        listOfDays = ['   '] * 42
        days = range(1, int(daysInMonth(year, month))+1) #list of days in month

        for day in days :
            #converts list of number to list of strings
            listOfDays[dayInWeek + (day - 1)] = "%3d" % day#accounts for blanks
      
        if month == 1 or month == 7 :
          
            listOfDays[listOfDays.index(' 1')] = '%s1' % STAR
      
        monthDetails[month] = (MONTHS[month], listOfDays)
      
    return monthDetails

def theEnd( ) :
    """Prints termination output."""
    print " Programed by Instructor"
    print "Date:", time.ctime()
    print "End of processing"

YEAR = int(raw_input('input year: '))
monthDetails = listMonthDays(YEAR)
print '%62d' % YEAR

for month in range(1, 13, 3) :
    left = formatCalendar(monthDetails[month]).split(' ')
    center = formatCalendar(monthDetails[month+1]).split(' ')
    right = formatCalendar(monthDetails[month+2]).split(' ')
    for row in range(len(left)) :
        print "%s %s %s" % (left[row], center[row], right[row])

theEnd( )