By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,676 Members | 2,262 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,676 IT Pros & Developers. It's quick & easy.

implementing a calendar class

P: 90
I would like to write a class CalculationDate which can deal with a date in numerical formation and text format and I have a nextDate method that returns the next day of the year. This class is written with a unit test which can test the proper treatment of leap year.

My question is how can I able to write a code to deal with the numerical formation and text format? I usually write a numerical one then write a function to convert it to text. If possible, can some one give an example code?
Nov 13 '07 #1
Share this Question
Share on Google+
16 Replies


bartonc
Expert 5K+
P: 6,596
I would like to write a class CalculationDate which can deal with a date in numerical formation and text format and I have a nextDate method that returns the next day of the year. This class is written with a unit test which can test the proper treatment of leap year.

My question is how can I able to write a code to deal with the numerical formation and text format? I usually write a numerical one then write a function to convert it to text. If possible, can some one give an example code?
isinstance() is the prefered way to handle parameters which may have different types:
Expand|Select|Wrap|Line Numbers
  1. >>> import time
  2. >>> timeStr = time.asctime()
  3. >>> timeStr
  4. 'Tue Nov 13 09:57:26 2007'
  5. >>> timeTup = time.localtime()
  6. >>> timeTup
  7. (2007, 11, 13, 10, 1, 43, 1, 317, 0)
  8. >>> class SmartTime(object):
  9. ...     def DateAndTime(self, timeStrOrTup):
  10. ...         if isinstance(timeStrOrTup, str):
  11. ...             return timeStrOrTup
  12. ...         if isinstance(timeStrOrTup, time.struct_time):
  13. ...             return time.strftime("%a %b %d %H:%M:%S %Y", timeStrOrTup)
  14. ...         
  15. >>> st = SmartTime()
  16. >>> st.DateAndTime(timeStr)
  17. 'Tue Nov 13 09:57:26 2007'
  18. >>> st.DateAndTime(timeTup)
  19. 'Tue Nov 13 10:01:43 2007'
  20. >>> 
Nov 13 '07 #2

bartonc
Expert 5K+
P: 6,596
isinstance() is the prefered way to handle parameters which may have different types:
Expand|Select|Wrap|Line Numbers
  1. >>> import time
  2. >>> timeStr = time.asctime()
  3. >>> timeStr
  4. 'Tue Nov 13 09:57:26 2007'
  5. >>> timeTup = time.localtime()
  6. >>> timeTup
  7. (2007, 11, 13, 10, 1, 43, 1, 317, 0)
  8. >>> class SmartTime(object):
  9. ...     def DateAndTime(self, timeStrOrTup):
  10. ...         if isinstance(timeStrOrTup, str):
  11. ...             return timeStrOrTup
  12. ...         if isinstance(timeStrOrTup, time.struct_time):
  13. ...             return time.strftime("%a %b %d %H:%M:%S %Y", timeStrOrTup)
  14. ...         
  15. >>> st = SmartTime()
  16. >>> st.DateAndTime(timeStr)
  17. 'Tue Nov 13 09:57:26 2007'
  18. >>> st.DateAndTime(timeTup)
  19. 'Tue Nov 13 10:01:43 2007'
  20. >>> 
And using the "varargs" syntax (p 338 of Learning Python by Mark Lutz), it might look like this:
Expand|Select|Wrap|Line Numbers
  1. >>> class SmartTime(object):
  2. ...     def DateAndTime(self, *args):
  3. ...         if isinstance(args[0], str):
  4. ...             return args[0]
  5. ...         if isinstance(args[0], time.struct_time):
  6. ...             return time.strftime("%a %b %d %H:%M:%S %Y", args[0])
  7. ...         return time.strftime("%a %b %d %H:%M:%S %Y", args)
  8. ...     
  9. >>> st = SmartTime()
  10. >>> st.DateAndTime(2007, 11, 13, 10, 1, 43, 1, 317, 0)
  11. 'Tue Nov 13 10:01:43 2007'
  12. >>> st.DateAndTime(timeStr)
  13. 'Tue Nov 13 09:57:26 2007'
  14. >>> st.DateAndTime(timeTup)
  15. 'Tue Nov 13 10:01:43 2007'
  16. >>> 
Nov 13 '07 #3

P: 90
I only need the date like 11-11-2007, not the time. And this date is set by user, not accorded to the system time because if using the system time, it automatically recognizes the leap year, and there is no nextDate method is used
Nov 13 '07 #4

P: 90
The way I explained the problem might no be clear.

- The date (including month, day, and year for example Tues August 27, 2007) should be inputed by user.

- The class should have some methods to figure out what is the text input what is the numeric input, and be be to do the nextDate() which returns the next day of the year, this has to deal with the leap year.
Question: how can I write this?
Nov 14 '07 #5

P: 75
if you want to know next day:

import datetime

now = datetime.date(2003, 8, 6)
difference1 = datetime.timedelta(days=1)
difference2 = datetime.timedelta(weeks=-2)

print "One day in the future is:", now + difference1

print "Two weeks in the past is:", now + difference2

hope that helps a little, here's some more reading: http://pleac.sourceforge.net/pleac_python/datesandtimes.html
Nov 14 '07 #6

P: 75
The way I explained the problem might no be clear.

- The date (including month, day, and year for example Tues August 27, 2007) should be inputed by user.

- The class should have some methods to figure out what is the text input what is the numeric input, and be be to do the nextDate() which returns the next day of the year, this has to deal with the leap year.
Question: how can I write this?
you are giving user an option to write month names in "text input"? usually if months are not in numerical format in application the user can choose the month from a list of months, not to write month name himself, or did I misunderstood this =)
Nov 14 '07 #7

P: 75
I'm just a noob, so sry if the code is not so nice looking
but what you think about this? =)

Expand|Select|Wrap|Line Numbers
  1. import datetime
  2.  
  3. while 1:  #loop while user has typed a proper date value
  4.  
  5.    the_date = raw_input("Please give a date in DD.MM.YYYY format\n")
  6.    date_table = the_date.split('.')  #splits "the_date" using . marks
  7.                                #date_table[0] = DD , date_table[1] = MM, etc...
  8.  
  9.    try: #checking if error happens when using datetime.date()
  10.       now = datetime.date(int(date_table[2]), int(date_table[1]), int(date_table[0]))  #int() converts string to int
  11.       break      #date value does exist, break from the while loop
  12.  
  13.    except:      #if there's error here it means that the date doesn't exist
  14.       print "You have type date in wrong format!, give day in (DD.MM.YYYY)\n"
  15.  
  16.  
  17. next_day = datetime.timedelta(days=1)
  18.  
  19. print "next day is", now + next_day
  20.  
ok, the printed next day is in totally different date format... (I'm lazy) but I think that it's easy to fix... :-D
Nov 14 '07 #8

P: 90
Thank you very much for helping me out.

Can I do this thing in the class?
Expand|Select|Wrap|Line Numbers
  1. #assume I've already had CalculationDate class, when I run this class
  2. >> CalculationDate(14,32,2004)
  3. invalid date, please enter a gain 12/29/2004
  4.  
Nov 14 '07 #9

KaezarRex
P: 52
To format the output, try something like this:
Expand|Select|Wrap|Line Numbers
  1. >>> import datetime
  2. >>> months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
  3. >>> dateA = datetime.date(2007, 5, 4)
  4. >>> print "%s %d, %d" % (months[dateA.month-1], dateA.day, dateA.year)
  5. May 4, 2007
Nov 14 '07 #10

KaezarRex
P: 52
Or this:
Expand|Select|Wrap|Line Numbers
  1. >>> dateA = datetime.date(2007, 5, 4)
  2. >>> output = dateA.ctime().replace("  ", " ").split(" ")
  3. >>> print "%s %s, %s" % (output[1], output[2], output[4])
  4. May 4, 2007
Nov 14 '07 #11

KaezarRex
P: 52
Or even better:
Expand|Select|Wrap|Line Numbers
  1. >>> dateA.strftime("%B %d, %Y") 
  2. 'May 14, 2007'
Nov 14 '07 #12

bvdet
Expert Mod 2.5K+
P: 2,851
Following is a class that does not use Python's datetime module:
Expand|Select|Wrap|Line Numbers
  1. import re
  2. patt = "[/.]"
  3.  
  4. class Dates(object):
  5.  
  6.     monthDict = dict(zip(range(1,13),['January', 'February', 'March', 'April', \
  7.                                       'May', 'June', 'July', 'August', 'September', \
  8.                                       'October', 'November', 'December']))
  9.     daysList1 = [31,28,31,30,31,30,31,31,30,31,30,31]
  10.     daysList2 = [31,29,31,30,31,30,31,31,30,31,30,31]
  11.  
  12.     def __init__(self, dateStr):
  13.         # dateStr is in the format month/day/year (xx/xx/xxxx) or month.day.year
  14.         self.dateStr = dateStr
  15.         try:
  16.             self.month, self.day, self.year = [int(s) for s in re.split(patt, dateStr)]
  17.         except:
  18.             raise ValueError, "Invalid date format"
  19.         self.month_str = self.monthStr()
  20.         self.day_num = self.dayNo()
  21.  
  22.     def isLeap(self, yr):        
  23.         if not yr % 4:
  24.             return 1
  25.         return 0
  26.  
  27.     def daysList(self, year):
  28.         return [self.daysList1, self.daysList2][self.isLeap(year)]
  29.  
  30.     def monthStr(self):
  31.         # return the text representation of the month number
  32.         try:
  33.             return self.monthDict[self.month]
  34.         except KeyError:
  35.             raise ValueError, "Invalid month number"
  36.  
  37.     def dayNo(self):
  38.         # return the day number in the year
  39.         if self.day < 1 or self.day > self.daysList(self.year)[self.month-1]:
  40.             raise ValueError, "Invalid day number"
  41.         return sum(self.daysList(self.year)[:self.month-1]) + self.day
  42.  
  43.     def monthDayYr(self, day_num):
  44.         # return a tuple of month, day, year given a day number
  45.         # day number is with respect to the year of the instance
  46.         idx = 0
  47.         year = self.year
  48.         while day_num < 1:
  49.             day_num += sum(self.daysList(year))
  50.             year -= 1
  51.         while True:
  52.             if day_num <= self.daysList(year)[idx]:
  53.                 return idx+1, day_num, year
  54.             day_num -= self.daysList(year)[idx]
  55.             idx += 1
  56.             if idx == 12:
  57.                 idx = 0
  58.                 year += 1
  59.  
  60.     def nextDay(self):
  61.         return self+1
  62.  
  63.     def preDay(self):
  64.         return self-1
  65.  
  66.     def __add__(self, days):
  67.         return Dates('/'.join([str(item) for item in self.monthDayYr(self.dayNo() + days)]))
  68.  
  69.     def __sub__(self, days):
  70.         return Dates('/'.join([str(item) for item in self.monthDayYr(self.dayNo() - days)]))
  71.  
  72.     def __str__(self):
  73.         return "%s %d, %d" % (self.month_str, self.day, self.year)
Nov 14 '07 #13

bartonc
Expert 5K+
P: 6,596
You guys do realize, don't you? All this and more is taken care of in the Calendar module.
Nov 15 '07 #14

bvdet
Expert Mod 2.5K+
P: 2,851
You guys do realize, don't you? All this and more is taken care of in the Calendar module.
Yes. Writing something myself is a lot more fun though.
Nov 15 '07 #15

P: 90
Following is a class that does not use Python's datetime module:
Expand|Select|Wrap|Line Numbers
  1. ...
  2.  
It is a little complicated and It seems that there is something I don't know. Like I never read something that when defining a method, we don't use self._something

assume that I have self._month, self._day, self._year has been property defined.
I have two list of maximum day for regular year and leap year.
I would like to write a nextDate() method to increase one day of current date, how can I write it?

Expand|Select|Wrap|Line Numbers
  1. class CalculationDate:
  2.             daysList1 = [31,28,31,30,31,30,31,31,30,31,30,31]
  3.             daysList2 = [31,29,31,30,31,30,31,31,30,31,30,31]
  4.             def __ini__(m, d, yr):
  5.                     self._month...
  6.                     self._day...
  7.                     self._year... # all of these things are written properly if user enters invalid information date, it will ask to change the date.
  8.             #now I would like to have a nextDay method:
  9.             def nextDay(self):
  10. # how can I write this
  11.  
Nov 15 '07 #16

bvdet
Expert Mod 2.5K+
P: 2,851
It is a little complicated and It seems that there is something I don't know. Like I never read something that when defining a method, we don't use self._something

assume that I have self._month, self._day, self._year has been property defined.
I have two list of maximum day for regular year and leap year.
I would like to write a nextDate() method to increase one day of current date, how can I write it?

Expand|Select|Wrap|Line Numbers
  1. class CalculationDate:
  2.             daysList1 = [31,28,31,30,31,30,31,31,30,31,30,31]
  3.             daysList2 = [31,29,31,30,31,30,31,31,30,31,30,31]
  4.             def __ini__(m, d, yr):
  5.                     self._month...
  6.                     self._day...
  7.                     self._year... # all of these things are written properly if user enters invalid information date, it will ask to change the date.
  8.             #now I would like to have a nextDay method:
  9.             def nextDay(self):
  10. # how can I write this
  11.  
The use of a leading underscore is for variables and methods intended to be non-public. I seldom make variables and methods non-public in the applications I have developed.

Did you notice that I included a nextDay() method in my post? The key is in the __add__(), monthDayYr(), and dayNo() methods. Method dayNo() returns the day number in the current year and does input validation on the day of the month. Method monthDayYr() returns a month, day, year tuple given a number of days with respect to the current year. Example:
Expand|Select|Wrap|Line Numbers
  1. >>> print a
  2. June 8, 2007
  3. >>> a.monthDayYr(a.dayNo())
  4. (6, 8, 2007)
  5. >>> a.monthDayYr(1)
  6. (1, 1, 2007)
  7. >>> a.monthDayYr(20000)
  8. (10, 3, 2061)
  9. >>> a.dayNo()
  10. 159
  11. >>> 
Method __add__() returns a Dates() object:
Expand|Select|Wrap|Line Numbers
  1. ....def __add__(self, days):
  2.         return Dates('/'.join([str(item) for item in self.monthDayYr(self.dayNo() + days)]))
The method nextDay() is now very simple:
Expand|Select|Wrap|Line Numbers
  1. ....def nextDay(self):
  2.         return self+1
Expand|Select|Wrap|Line Numbers
  1. >>> print d
  2. December 31, 2000
  3. >>> d.nextDay()
  4. <__main__.Dates object at 0x00DC70B0>
  5. >>> print d.nextDay()
  6. January 1, 2001
  7. >>> 
Following is an example using a Dates() object to parse the input and the Python datetime module:
Expand|Select|Wrap|Line Numbers
  1. if __name__ == '__main__':
  2.     import datetime
  3.     d = Dates('6/8/2007')
  4.     dt = datetime.datetime(d.year, d.month, d.day)
  5.     oneday = datetime.timedelta(days=1)
  6.     newdate = dt + oneday
  7.     print newdate
Output: >>> 2007-06-09 00:00:00

HTH
Nov 15 '07 #17

Post your reply

Sign in to post your reply or Sign up for a free account.