Starting from:

$35

Hw 12 How to get a Date!

CS115 – Hw 12
How to get a Date!
This week's homework will guide you through creating a class named Date which will allow you to do
computations on dates.
The Date class
Grab the starting file date_template.py
Save your copy as date.py (and change Hw 11 to Hw 12 if you like).
Take a moment to look over this file as it stands so far...
Notice that in this Date class there are three attributes, also known as data members:
• A data member holding the month (this is self.month)
• A data member holding the day of the month (this is self.day)
• A data member holding the year (this is self.year)
Note that self is used to denote any object value of class Date!
Methods are just functions...
Object-oriented programming tends to have some of its own names for familiar things. For
example, method is the "OOP" name for function. In particular, a method is a function whose first input
is self!
Note that the Date class has an __init__ method and a __str__ method. As we've discussed in
class, Python expects to see these special methods in virtually every class. The double underscores
before and after these method names indicate that these methods are special methods that Python
knows to look for. In the case of __init__, this is the method that Python looks for when making a
new Date object. In the case of __str__, this is the method that Python looks for when it needs
to represent the object as a string.
Notice the line
 s = '%02d/%02d/%04d' % (self.month, self.day, self.year)
in the str method. This constructs a string with the month, day, and the year, formatted very nicely to
have exactly two digits places for the month, two digit places for the day, and four for the year. If you
would like to learn more about fancy string formatting, you can look at the string documentation page.
We've also defined our own isLeapYear method. There are no double-underscores here, so Python
didn't "expect" this method, but it certainly doesn't "object" to it either (sorry for the bad pun - we clearly
have no class!).
CS115 – Hw 12
Note on "method"
Traditionally, functions called by objects are called methods. There is no really good reason for this. They
are functions—the only thing special about them is that they are defined in a class and they are called
after a dot or period following the name of an object. For example, you might try these:
>>> d = Date(11, 8, 2011)
>>> d.isLeapYear()
False
>>> d2 = Date(3, 15, 2012)
>>> d2.isLeapYear()
True
>>> Date(1, 1, 1900).isLeapYear() # no variable needed!
False
What's up with self?
One odd thing about the above example is that three different objects of type Date are calling
the same isLeapYear code. How does the isLeapYear method tell the different objects apart?
The method does not know the name of the variable that calls it! In fact, in the third example, there
is no variable name! The answer is self. The self variable holds the object that calls the method,
including all of its data members.
This is why self is always the first input to all of the methods in the Date class (and in any class that
you define!): because self is how the method can access the individual data members in the object that
called it.
Please notice also—this means that a method always has at least one input argument, namely self.
However, this value is passed in implicitly when the method is called. For example, isLeapYear is
invoked in the example above as Date(1,1,1900).isLeapYear(), and Python automatically
passed self, in this case the object Date(1,1,1900), as the first input to the isLeapYear method.
Testing your initial Date class
Just to get a feel for how to test your new datatype, try out the following calls:
# create an object named d with the constructor
>>> d = Date(11, 9, 2011)
# show d's value
>>> d
11/09/2011
# a printing example
>>> print 'Wednesday is', d
Wednesday is 11/09/2011
CS115 – Hw 12
# create another object named d2
# of *the same date*
>>> d2 = Date(11, 9, 2011)
# show its value
>>> d2
11/09/2011
# are they the same?
>>> d == d2
False
# look at their memory locations
>>> id(d) # return memory address
413488 # your result will be different...
>>> id(d2) # again...
430408 # this should differ from above!
# check if d2 is in a leap year -- it's not!
>>> d2.isLeapYear()
False
# yet another object of type Date
# next year's NYDay
>>> d3 = Date(1, 1, 2012)
# check if d3 is in a leap year
>>> d3.isLeapYear()
True
copy and equals
For this part, you should paste the following two methods (code provided) into your Date class and then
test them. We are providing the code so that you have several more examples of what it is like to define
functions inside a class:
• copy(self):
Here is the code for this method:
 def copy(self):
 '''Returns a new object with the same month, day, year
 as the calling object (self).'''
 dnew = Date(self.month, self.day, self.year)
 return dnew
This method returns a newly constructed object of type Date with the same month, day, and year that the
calling object has. Remember that the calling object is named self, so the calling object's month
is self.month, the calling object's day is self.day, and so on.
CS115 – Hw 12
Since you want to create a newly constructed object, you need to call the constructor! This is what you
see happening in the copy method.
Try out these examples, which use this year's New Year's Day...
>>> d = Date(1, 1, 2011)
>>> d2 = d.copy()
>>> d
01/01/2011
>>> d2
01/01/2011
>>> id(d)
430568 # your memory address may differ
>>> id(d2)
413488 # but d2 should be different from d!
>>> d == d2
False # thus, this should be false...
• equals(self, d2):
Here is the code for this method:
 def equals(self, d2):
 '''Decides if self and d2 represent the same calendar date,
 whether or not they are the in the same place in memory.'''
 return self.year == d2.year and self.month == d2.month and \
 self.day == d2.day
This method should return True if the calling object (named self) and the input (named d2) represent
the same calendar date. If they do not represent the same calendar date, this method should
return False. The examples above show that the same calendar date may be represented at multiple
locations in memory—in that case the == operator returns False. This method can be used to see if two
objects represent the same calendar date, regardless of whether they are at the same location in
memory.
Try these examples (after reloading your file) to get the hang of how this equals method works:
>>> d = Date(1, 1, 2011)
>>> d2 = d.copy()
>>> d
01/01/2011
>>> d2
01/01/2011
>>> d == d2
CS115 – Hw 12
False # this should be False!
>>> d.equals(d2)
True # but this should be True!
>>> d.equals(Date(1, 1, 2011)) # no name needed!
True
>>> d == Date(1, 1, 2011) # tests memory addresses
False # so it should be False
Now, the next part of the homework asks you to implement a few methods for the Date class from
scratch.
Be sure to add a docstring to each of the methods you write! (Recall that the term method refers to a
function that is a member of a user-defined class... .)
tomorrow
First, add the following method to your Date class (you may have notes that help...):
• tomorrow(self):
This method should NOT RETURN ANYTHING! Rather, it should change the calling object so
that it represents one calendar day after the date it originally represented. This means
that self.day will definitely change. What's more, self.month and self.year might change.
• You may find the list DIM = (0,31,28,31,30,31,30,31,31,30,31,30,31) a useful line to
have at the very top of your function... !
That list makes it easy to determine how many days there are in any particular month (self.month).
Testing tomorrow
To test your tomorrow method, you should try several test cases of your own design. Here are a couple
of randomly chosen ones to get you started:
>>> d = Date(12, 31, 2010)
>>> d
12/31/2010
>>> d.tomorrow()
>>> d
CS115 – Hw 12
01/01/2011
>>> d = Date(2, 28, 2012)
>>> d.tomorrow()
>>> d
02/29/2012
>>> d.tomorrow()
>>> d
03/01/2012
yesterday
Next, add the following method to your Date class:
• yesterday(self):
Like tomorrow, this method should not return anything. Again, it should change the calling object
so that it represents one calendar day before the date it originally represented.
Again, self.day will definitely change, and self.month and self.year might change.
Testing yesterday
To test your yesterday method, you should try several test cases of your own design. Here are the
reverses of the previous tests:
>>> d = Date(1, 1, 2011)
>>> d
1/1/2011
>>> d.yesterday()
>>> d
12/31/2010
>>> d = Date(3, 1, 2012)
>>> d.yesterday()
>>> d
02/29/2012
>>> d.yesterday()
>>> d
02/28/2012
addNDays
Next, add the following method to your Date class:
CS115 – Hw 12
• addNDays(self, N):
This method only needs to handle nonnegative integer inputs N. Like the tomorrow method, this
method should not return anything. Rather, it should change the calling object so that it
represents N calendar days after the date it originally represented.
Don't copy code from the tomorrow method! Instead, consider how you could call the tomorrow method
inside a for loop in order to implement this!
In addition, this method should print all of the dates from the starting date to the finishing date, inclusive of
both endpoints. Remember that the line print self can be used to print an object from within one of
that object's methods! See below for examples of output.
Testing addNDays
To test your addNDays method, you should try several test cases of your own design. Here are a couple
to start with –
>>> d = Date(11, 9, 2011)
>>> d.addNDays(3)
11/09/2011
11/10/2011
11/11/2011
11/12/2011
>>> d
11/12/2011
>>> d = Date(11, 11, 2011) # the near future
>>> d.addNDays(1283)
11/11/2011
11/12/2011
... lots of dates skipped ...
5/16/2015
5/17/2015
>>> d
5/17/2015 # graduation! (if not before...)
You can check your own additions with this website: http://www.timeanddate.com/date/dateadd.html.
Note that 1752 was a weird year for the United States/colonies' calendar—especially September!
However, your Date class does not need to handle these unusual situations (and shouldn't do so, so that
we can test things consistently!).
subNDays
CS115 – Hw 12
Next, include the following method in your Date class:
• subNDays(self, N):
This method only needs to handle nonnegative integer inputs N. Like the addNDays method, this
method should not return anything. Rather, it should change the calling object so that it
represents N calendar days before the date it originally represented. You might consider
using yesterday and a for loop to implement this!
In addition, this method should print all of the dates from the starting date to the finishing date, inclusive
of both endpoints. Again, this mirrors the addNDays method. See below for examples of the output.
Testing subNDays
Try reversing the above test cases!
isBefore
Next, add the following method to your Date class:
• isBefore(self, d2):
This method should return True if the calling object is a calendar date before the input
named d2 (which will always be an object of type Date). If self and d2 represent the same day,
this method should return False. Similarly, if self is after d2, this should returnFalse.
It might be worth mentioning that you could pass a string or a float or an integer as the input to
this isBefore method. In this case, your code will likely raise a TypeError. We won't do this to your
code! Python relies on the user to keep track of the types being used.
Testing isBefore
To test your isBefore method, you should try several test cases of your own design. Here are a few to
get you started:
>>> d = Date(11, 11, 2011)
>>> d2 = Date(1, 1, 2012)
>>> d.isBefore(d2)
True
>>> d2.isBefore(d)
False
>>> d.isBefore(d)
False
isAfter
CS115 – Hw 12
Next, add the following method to your Date class:
• isAfter(self, d2):
This method should return True if the calling object is a calendar date after the input
named d2 (which will always be an object of type Date). If self and d2 represent the same day,
this method should return False. Similarly, if self is before d2, this should returnFalse.
You can emulate your isBefore code here OR you might consider how to use
the isBefore and equals methods to write isAfter.
Testing isAfter
To test your isAfter method, you should try several test cases of your own design. For example, you
might reverse the examples shown above for isBefore.
diff
Next, add the following method to your Date class:
• diff(self, d2):
This method should return an integer representing the number of days between self and d2.
You can think of it as returning the integer representing
 self - d2
But dates are more complicated than integers!! So, implementing diff will be more involved than this!
See below for hints...
One crucial point: this method should NOT change self NOR should it change d2! You should
create and manipulate copies of self and d2, so that the originals remain unchanged.
Also, The sign of the return value is important! Consider these three cases:
• If self and d2 represent the same calendar date, this method should return 0.
• If self is before d2, this method should return a negative integer equal to the number of days
between the two dates.
• If self is after d2, this method should return a positive integer equal to the number of days
between the two dates.
Two approaches not to use!
CS115 – Hw 12
• First, don't try to subtract years, months, and days between two dates...this is way too errorprone.
• By the same token, however, don't use addNDays or subNDays to implement
your diff method. Checking all of the possible difference amounts will be too slow! Rather,
implement diff in the same style as those two methods: namely,
using yesterday and/or tomorrowand loops.
How do we do this?
• You will want to use the tomorrow and yesterday methods you've already written -- inside
a while loop!
• The test for the while loop may be something like while day1.isBefore( day2 ): or it may
use isAfter...
• Use yesterday or tomorrow within the loop and count the number of times you need to loop
before it finishes...
Testing diff
To test your diff method, you should try several test cases. Here are two relatively nearby pairs of
dates:
>>> d = Date(11,9,2011)
>>> d2 = Date(12,16,2011)
>>> d2.diff(d)
37
>>> d.diff(d2)
-37
>>> d
11/09/2011
>>> d2 # make sure they did not change...
12/16/2011
# Here are two that pass over a leap year...
>>> d = Date(11,9,2011)
>>> d3 = Date(5, 18, 2012)
>>> d3.diff(d)
191
And here are two relatively distant pairs of dates:
>>> d = Date(11, 9, 2011)
>>> d.diff(Date(1, 1, 1899))
41219
>>> d.diff(Date(1, 1, 2101))
-32560
CS115 – Hw 12
You can check other differences at www.timeanddate.com/date/duration.html .
dow
Next, add the following method to your Date class:
• dow(self):
This method should return a string that indicates the day of the week (dow) of the object (of
type Date) that calls it. That is, this method returns one of the following strings: ‘Monday’,
‘Tuesday’, ‘Wednesday’, ‘Thursday’, ‘Friday’, ‘Saturday’, or ‘Sunday’.
Hint: How might it help to find the diff from a known date, like Wednesday, November 9, 2011? How
might the mod (%) operator help?
Testing dow
To test your dow method, you should try several test cases of your own design. Here are a few to get you
started:
>>> d = Date(12, 7, 1941)
>>> d.dow()
'Sunday'
>>> Date(10, 28, 1929).dow() # dow is appropriate: crash day!
'Monday'
>>> Date(10, 19, 1987).dow() # ditto!
'Monday'
>>> d = Date(1, 1, 2100)
>>> d.dow()
'Friday'
You can check your days of the week at www.timeanddate.com/calendar/ by entering the year you're
interested in.
Congratulations -- you now have a Date class whose objects can compute the differences and the days
of the week for any calendar dates at all!

More products