CSc 120: Dates
Background
This problem involves managing a database of dates and events,
e.g., for a calendar app or history website.
Problem Description
Suppose you wanted to offer a website or app to manage a database of dates
and events. Such a database might be used to look up dates in the past
("on this date in history...", as in the sites mentioned above);
or they might be used as a calendar service to provide reminders for future
events. In either case, you need a program that can record and look up
strings (i.e., events) associated with dates.
One catch here is reasoning about dates.
People use many different formats
to write dates, e.g., "December 25, 2016", "2016-12-25",
and "12/25/2016", all of which represent the same date. The
format that was used to insert an event into the database may or may not be
the same as the format used to look up up that date. Your program therefore
needs a way to reason about dates in different formats. This problem
involves writing a class to maintain information about dates and events
and reason about dates in different formats. The idea is to read a file
containing a series of operations, where each operation refers to a
database of dates and events, and process each operation in turn.
Input Formats
The input to the program is read from a file (see Expected Behavior below).
Each line of the file is an operation, and is in one of the following two formats:
I Date : Event
R Date
The fields in an operation are as follows:
- Date
-
This specifies a date. It can be in any of the following three formats.
-
yyyy-mm-dd,
where yyyy is a 4-digit sequence
giving the year; mm is a 1- or 2-digit sequence giving the
month; and dd is a 1- or 2-digit sequence giving the date.
Example: 2017-02-31
-
mm/dd/yyyy,
where yyyy is a 4-digit sequence
giving the year; mm is a 1- or 2-digit sequence giving the
month; and dd is a 1- or 2-digit sequence giving the date.
Example: 02/31/2017.
-
MonthName dd yyyy, where MonthName is
a three-letter sequence giving the name of a month
(one of: Jan, Feb, Mar, Apr, May,
Jun, Jul, Aug, Sep, Oct, Nov,
Dec); dd is a 1- or 2-digit sequence giving the date; and
yyyy is a 4-digit sequence giving the year.
Example: Feb 31 2017
NOTE:
To simplify programming, we will assume that all months have 31 days.
- Event
-
This is a string starting at the first non-whitespace character after
the colon ":" following the date and going as
far as the end of the line.
Examples of operations are:
I 2017-01-16 : Martin Luther King Day
I Mar 31 1997: Arizona Wildcats win National Basketball Title
R 03/31/1997
The first of these inserts the event "Martin Luther King
Day" for the date Jan 16, 2017 into the
calendar. The second adds the event "Arizona Wildcats win
National Basketball Title" for the date March 31,
1997.
The third item retrieves and prints out all events for the date March 31, 1997.
Expected Behavior
Write a Python program, in a file dates.py, that maintains a
collection of Date objects, each of which has associated with
a set of strings that refer to events for that date, processing these objects
in accordance with operations
read from an input file. Your program should behave as follows:
-
Use input() (without any argument) to read the name of an
input file.
-
Read the file specified and process its contents as described below.
Process the operation specified on each line as follows:
-
OpType = I. Add the Event string to the collection
of events for the date specified (duplicates are OK).
If there is no existing Date object for that date,
create one and initialize its collection of events to the Event
string specified.
-
OpType = R. Print out the event strings for that date
one per line (see Output Format below).
If there is no existing Date object for that date,
do not print anything.
Dates are considered equal if their canonical representations (see below)
are the same.
Some examples of input files and generated output are shown
here.
Canonical Representation of Dates
A date with year yyyy, month mm, and day dd, where
yyyy, mm, and dd are strings of digits,
has a canonical (i.e., standard) representation given by
"{:d}-{:d}-{:d}".format(
int(yyyy ),
int(mm),
int(dd))
The reason for converting yyyy, mm, and dd to
numbers using int() and then back to strings is to
remove any leading zeros.
Example:
Input format | Canonical representation |
Mar 7 1997
Mar 07 1997
03/07/1997
3/7/1997
1997-3-07
1997-03-7
|
1997-3-7 |
Output Format
Print out the events for a given date one event per line using the statement
print("{}: {}".format(date_canonical, event))
where date_canonical is the canonical representation of
the date, and event is an event for that date.
The order in which events are printed out need not be the same as the
order in which they were initially specified.
If there are multiple events for a given date, they should be printed in alphabetical order.
Programming Requirements
Your program should implement the following classes:
-
class Date
-
An instance of this class describes a date.
Attributes: These should include:
-
the canonical representation of the date
-
the associated events (a collection of strings, e.g., a list or set).
Methods: These should include:
-
__init__(self, date, event), where
date is the canonical representation of the date and
event is a string for an event.
-
Getters for the attributes.
(You don't really need setters for this
class for this problem because once a Date object has
been initialized it is not subsequently modified.)
-
__str__() and, optionally, a __repr()__ method.
-
A method to add an event (a string) to the collection of
events for a Date object;
-
A method to convert a date string from the input format to the
canonical representation. (see below)
-
class DateSet
-
An instance of this class describes a collection of dates.
Attributes: These should include:
-
a collection of Date objects.
(A dictionary is a likely data structure for this. If you used this, what
might you use as keys?).
Methods: These should include:
-
__init__();
-
A method to add a Date object to the collection of
such objects.
-
optionally, __str__() and
__repr()__ methods.
Additionally, you will need code for the following:
-
To read in an input file name (use input() without arguments),
read a series of operations from this file (see Input Formats above), and
process them as specified under Expected Behavior above. You can do
this in either of two ways:
-
you can put this code in a method for the DateSet
class; or
-
you can put this code in a function that is not within any class (just like
main()).
-
To convert a date string to canonical format. You can put this code in a function
that is not within any class (just like main()).
Your program should be appropriately modularized. In particular,
other than the code mentioned above for processing input and converting
dates to their canonical form, your code should
be placed in methods in the appropriate class.
Errors
The following are errors.
-
The input file cannot be read.
Program response: Quit after printing the error message below.
(Use a try-except construct for this.)
“ERROR: Could not open file “ + filename
-
The operation is not I or R.
Program response:
Quit after printing the error message below.
“ERROR: Illegal operation on line “ + input_line
-
A month is greater than 12 or a day of the month is greater than 31.
Program response:
Quit after printing the error message below.
“ERROR: Illegal date on line “ + input_line
The tester will fully exercise all error cases that we expect you to handle. In other words, if you pass all error-producing tests, you can assume your error handling is fully correct and complete.
Examples
Some examples are shown
here.