Make sure the gtd base path has a trailing slash.
[matthijs/upstream/mobilegtd.git] / src / model / datetime.py
1 import time as t
2 import calendar
3 from types import InstanceType
4     
5 MINYEAR = 1
6 MAXYEAR = 9999
7     
8 class DaysInMonth:
9     def calculate(self, year, month):
10         return [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] + (month == 2 and self.isleap(year))
11     
12     def isleap(self, year):
13         return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
14     
15     def test(self):
16         passed = True
17         for year in range (1,9999):
18             for month in range(1,12):
19                 if DaysInMonth().calculate(year, month) <> calendar.monthrange(year, month)[1]:
20                     print "Failed on %s-%s."%(year, month)
21                     passed = False
22         if not passed:
23             print "FAILED"
24         else:
25             print "PASSED"
26         return passed
27         
28     def weekday(self, year, month, day):
29         secs = mktime((year, month, day, 0, 0, 0, 0, 0, 0))
30         tuple = localtime(secs)
31         return tuple[6]
32     
33     
34
35 daysInMonth = DaysInMonth()
36        
37 class datetime:
38     def __init__(self,year,month,day,hour=0,minute=0,second=0,microsecond=0):
39         dates = ['year','month','day','hour','minute']
40         counter = 0
41         for item in [year,month,day,hour,minute]:
42             if type(item) not in [type(1), type(1L)]:
43                 raise TypeError("The variable '%s' should be an integer."%dates[counter])
44             counter += 1
45         
46         if type(second) not in [type(1), type(1L)]:# and type(second) <> type(1.004):
47             raise ValueError("The variable 'second' should be an Integer or a Long.")# or a float.")
48
49         # Very basic error checking and initialisation.
50         if year < MINYEAR or year > MAXYEAR:
51             raise ValueError('The year value must be between %s and %s inclusive.'%(MINYEAR, MAXYEAR))
52         else:
53             self.year = year
54         if month < 1 or month > 12:
55             raise ValueError('The month value must be between 1 and 12 inclusive.')
56         else:
57             self.month = month
58         if day < 1 or day > daysInMonth.calculate(year, month):
59             raise ValueError('The day value must be between 1 and %s inclusive.'%daysInMonth.calculate(year, month))
60         else:    
61             self.day = day
62         if hour < 0 or hour > 23:
63             raise ValueError('The hour value must be between 0 and 23 inclusive.')
64         else:
65             self.hour = hour
66         if minute < 0 or minute > 59:
67             raise ValueError('The minutes value must be between 0 and 59 inclusive.')
68         else:
69             self.minute = minute
70         if second < 0 or second > 59:
71             raise ValueError('The seconds value must be between 0 and 59 inclusive.')
72         else:    
73             self.second = second 
74         if microsecond < 0 or microsecond > 1000000:
75             raise ValueError('The microseconds value must be between 0 and 1000000 inclusive.')
76         else:    
77             self.microsecond = microsecond
78     
79     def now(self=None):
80         now = t.localtime()
81         return datetime(now[0],now[1],now[2],now[3],now[4],now[5])
82     now = staticmethod(now)
83
84 #
85 # Comparison Operators.
86 #
87
88     def _compareDate(self, other):
89         if self.year == other.year:
90             if self.month == other.month:
91                 if self.day == other.day:
92                     return 0
93                 elif self.day > other.day:
94                     return 1
95                 else:
96                     return -1
97             elif self.month > other.month:
98                 return 1
99             else:
100                 return -1
101         elif self.year > other.year:
102             return 1
103         else:
104             return -1
105             
106     def _compareTime(self, other):
107         if self.hour == other.hour:
108             if self.minute == other.minute:
109                 if self.second == other.second:
110                     return 0
111                 elif self.second > other.second:
112                     return 1
113                 else:
114                     return -1
115             elif self.minute > other.minute:
116                 return 1
117             else:
118                 return -1
119         elif self.hour > other.hour:
120             return 1
121         else:
122             return -1
123             
124                         
125     def __cmp__(self, other):
126         if type(other) is type(None):
127             raise Exception('Comparison of %s (%s) with %s (%s) is not supported'%(self,type(self),other,type(other)))
128         elif type(other) is InstanceType:
129 #            if other.__class__.__name__ == self.__class__.__name__:
130                 if other.__class__.__name__ == 'date':
131                     return self._compareDate(other)
132                 elif other.__class__.__name__ == 'time':
133                     return self._compareTime(other)
134                 elif other.__class__.__name__ == 'datetime':
135                     date = self._compareDate(other)
136                     if date == 0:
137                         return self._compareTime(other)
138                     else:
139                         return date
140                 else:
141                     raise Exception('Comparison of %s (%s) with %s (%s) is not supported'%(self,type(self),other,type(other)))
142 #            else:
143 #                raise Exception('Comparison of %s (%s) with %s (%s) is not supported'%(self,self.__class__,other,other.__class__))
144         else:
145             raise Exception('Comparison of %s (%s) with %s (%s) is not supported'%(self,type(self),other,type(other)))
146             
147     def __eq__(self, other):
148         if type(other) is InstanceType:
149             if other.__class__.__name__ == self.__class__.__name__:
150                 if other.__class__.__name__ == 'date':
151                     if self._compareDate(other) == 0:
152                         return 1
153                     else:
154                         return 0
155                 elif other.__class__.__name__ == 'time':
156                     if self._compareTime(other) == 0:
157                         return 1
158                     else:
159                         return 0
160                 elif other.__class__.__name__ == 'datetime':
161                     date = self._compareDate(other)
162                     if date == 0:
163                         if self._compareTime(other) == 0:
164                             return 1
165                         else:
166                             return 0
167                     else:
168                         return 0
169                 else:
170                     return 0
171             else:
172                 return 0
173         else:
174             return 0
175             
176     def __ne__(self, other):
177         if self.__eq__(other):
178             return 0
179         else:
180             return 1
181             
182     def __str__(self):
183         return self.isoformat()
184
185     def __repr__(self):
186         return "datetime.datetime(%s,%s,%s,%s,%s,%s)"%(self.year, self.month, self.day, self.hour, self.minute, self.second)
187     
188     def __getitem__(self, item):
189         if item == 'year':
190             return self.year
191         elif item == 'month':
192             return self.month
193         elif item == 'day':
194             return self.day
195         elif item == 'hour':
196             return self.hour
197         elif item == 'minute':
198             return self.minute
199         elif item == 'second':
200             return self.second
201         else:
202             raise KeyError("'%s' is not a valid attribute for a Date class."%item)
203
204 #
205 # Formatting
206 #
207
208     def _addZeros(self,num,s):
209         s = str(s)
210         while( len(s) < num ):
211             s = '0'+s
212         return s
213         
214     def _isodate(self):
215         return str(self._addZeros(4,self.year))+"-"+str(self._addZeros(2,self.month))+"-"+str(self._addZeros(2,self.day))
216
217     def _isotime(self):
218         return str(self._addZeros(2,self.hour))+":"+str(self._addZeros(2,self.minute))+":"+str(self._addZeros(2,self.second))#str(self._addZeros(2,int(self.second)))+'.'+s
219    
220     def strftime(self, format):
221         #raise Exception(self.timetuple())
222         return t.strftime(format, self.timetuple()) 
223
224     
225
226 #
227 # Conversion
228 #
229
230     def timetuple(self):
231         sql =  self.isoformat()
232         wday = calendar.weekday(int(sql[0:4]),int(sql[5:7]),int(sql[8:10]))
233         return (int(sql[0:4]),int(sql[5:7]),int(sql[8:10]),int(sql[11:13]),int(sql[14:16]),int(sql[17:19]),wday,0,-1)#,0,0,-1) ,0,0,-1) 
234         
235     def isoformat(self):
236         return self._isodate() + ' ' + self._isotime()
237
238     
239 class date(datetime):
240     def __init__(self,year,month,day):
241         
242         dates = ['year','month','day']
243         counter = 0
244         for item in [year,month,day]:
245             if type(item) not in [ type(1), type(1L)]:
246                 raise TypeError("The variable '%s' should be an Integer or a Long."%dates[counter])
247             counter += 1
248         
249      
250         # Very basic error checking and initialisation.
251         if year < MINYEAR or year > MAXYEAR:
252             raise ValueError('The year value must be between %s and %s inclusive.'%(MINYEAR, MAXYEAR))
253         else:
254             self.year = year
255         if month < 1 or month > 12:
256             raise ValueError('The month value must be between 1 and 12 inclusive.')
257         else:
258             self.month = month
259         if day < 1 or day > daysInMonth.calculate(year, month):
260             raise ValueError('The day value must be between 1 and %s inclusive.'%daysInMonth.calculate(year, month))
261         else:    
262             self.day = day
263         
264     def __repr__(self):
265         return "datetime.date(%s,%s,%s)"%(self.year,self.month, self.day)
266         
267     def isoformat(self):
268         return self._isodate()
269         
270     def timetuple(self):
271         sql = self.isoformat()
272         wday = calendar.weekday(int(sql[0:4]),int(sql[5:7]),int(sql[8:10]))
273         return (int(sql[0:4]),int(sql[5:7]),int(sql[8:10]),0,0,0,wday,0,-1)
274     
275     def now(self=None):
276         now = t.localtime()
277         return date(now[0],now[1],now[2])
278     now = staticmethod(now)
279
280     def in_x_days(number_of_days=0):
281         secs = t.mktime(t.localtime())
282         day_secs = secs+24*60*60*number_of_days
283         day = t.localtime(day_secs)
284         return date(day[0],day[1],day[2])
285     in_x_days=staticmethod(in_x_days)  
286     
287     def tomorrow():
288         return date.in_x_days(1)
289     tomorrow = staticmethod(tomorrow)
290         
291 class time(datetime):
292     
293     def __init__(self,hour=0,minute=0,second=0,microsecond=0):
294         
295         dates = ['hour','minute']
296         counter = 0
297         for item in [hour,minute]:
298             if type(item) not in [type(1), type(1L)]:
299                 raise TypeError("The variable '%s' should be an Integer or a Long."%dates[counter])
300             counter += 1
301         
302         if type(second) <> type(1):# and type(second) <> type(1.004):
303             raise ValueError("The variable 'second' should be an integer.")# or a float.")
304
305         # Very basic error checking and initialisation.
306        
307         if hour < 0 or hour > 23:
308             raise ValueError('The hour value must be between 0 and 23 inclusive.')
309         else:
310             self.hour = hour
311         if minute < 0 or minute > 59:
312             raise ValueError('The minutes value must be between 0 and 59 inclusive.')
313         else:
314             self.minute = minute
315         if second < 0 or second > 59:
316             raise ValueError('The seconds value must be between 0 and 59 inclusive.')
317         else:    
318             self.second = second
319         if microsecond < 0 or microsecond > 1000000:
320             raise ValueError('The microseconds value must be between 0 and 1000000 inclusive.')
321         else:    
322             self.microsecond = microsecond
323         
324     def __repr__(self):
325         return "datetime.time(%s,%s,%s)"%(self.hour, self.minute, self.second)
326         
327     def isoformat(self):
328         return self._isotime()
329         
330     def timetuple(self):
331         raise AttributeError('time objects do not have a timetuple method.')
332
333     def now(self):
334         now = t.localtime()
335         return time(now[3],now[4],now[5])
336