comparison roundup/date.py @ 964:832d1209aaa2

Preparing to turn back on link/unlink journal events. By default these are turned off. I've: - fixed back_anydbm so it can journal those events again (had broken it with recent changes) - changed the serialisation format for dates and intervals to use a numbers-only (and sign for Intervals) string instead of tuple-of-ints. Much smaller.
author Richard Jones <richard@users.sourceforge.net>
date Wed, 21 Aug 2002 07:07:27 +0000
parents a568596dbea7
children 5252cc77eaa0
comparison
equal deleted inserted replaced
963:6010f0078800 964:832d1209aaa2
13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17 # 17 #
18 # $Id: date.py,v 1.23 2002-07-18 23:07:08 richard Exp $ 18 # $Id: date.py,v 1.24 2002-08-21 07:07:27 richard Exp $
19 19
20 __doc__ = """ 20 __doc__ = """
21 Date, time and time interval handling. 21 Date, time and time interval handling.
22 """ 22 """
23 23
73 <Date 2000-01-25.00:00:00> 73 <Date 2000-01-25.00:00:00>
74 >>> Date("08-13.22:13", -5) 74 >>> Date("08-13.22:13", -5)
75 <Date 2000-08-14.03:13:00> 75 <Date 2000-08-14.03:13:00>
76 >>> Date("14:25", -5) 76 >>> Date("14:25", -5)
77 <Date 2000-06-25.19:25:00> 77 <Date 2000-06-25.19:25:00>
78
79 The date format 'yyyymmddHHMMSS' (year, month, day, hour,
80 minute, second) is the serialisation format returned by the serialise()
81 method, and is accepted as an argument on instatiation.
78 ''' 82 '''
79 def __init__(self, spec='.', offset=0): 83 def __init__(self, spec='.', offset=0):
80 """Construct a date given a specification and a time zone offset. 84 """Construct a date given a specification and a time zone offset.
81 85
82 'spec' is a full date or a partial form, with an optional 86 'spec' is a full date or a partial form, with an optional
208 self.day, self.hour, self.minute, self.second, 0, 0, 0)) 212 self.day, self.hour, self.minute, self.second, 0, 0, 0))
209 if str[0] == '0': return ' ' + str[1:] 213 if str[0] == '0': return ' ' + str[1:]
210 return str 214 return str
211 215
212 def set(self, spec, offset=0, date_re=re.compile(r''' 216 def set(self, spec, offset=0, date_re=re.compile(r'''
213 (((?P<y>\d\d\d\d)-)?((?P<m>\d\d?)-(?P<d>\d\d?))?)? # yyyy-mm-dd 217 (((?P<y>\d\d\d\d)-)?((?P<m>\d\d?)-(?P<d>\d\d?))?)? # yyyy-mm-dd
214 (?P<n>\.)? # . 218 (?P<n>\.)? # .
215 (((?P<H>\d?\d):(?P<M>\d\d))?(:(?P<S>\d\d))?)? # hh:mm:ss 219 (((?P<H>\d?\d):(?P<M>\d\d))?(:(?P<S>\d\d))?)? # hh:mm:ss
216 (?P<o>.+)? # offset 220 (?P<o>.+)? # offset
217 ''', re.VERBOSE)): 221 ''', re.VERBOSE), serialised_re=re.compile('''
222 (?P<y>\d{4})(?P<m>\d{2})(?P<d>\d{2}) # yyyymmdd
223 (?P<H>\d{2})(?P<M>\d{2})(?P<S>\d{2}) # HHMMSS
224 ''', re.VERBOSE)):
218 ''' set the date to the value in spec 225 ''' set the date to the value in spec
219 ''' 226 '''
220 m = date_re.match(spec) 227 m = serialised_re.match(spec)
221 if not m: 228 if not m:
222 raise ValueError, _('Not a date spec: [[yyyy-]mm-dd].[[h]h:mm[:ss]]' 229 m = date_re.match(spec)
223 '[offset]') 230 if not m:
231 raise ValueError, _('Not a date spec: [[yyyy-]mm-dd].'
232 '[[h]h:mm[:ss]][offset]')
233
224 info = m.groupdict() 234 info = m.groupdict()
225 235
226 # get the current date/time using the offset 236 # get the current date/time using the offset
227 y,m,d,H,M,S,x,x,x = time.gmtime(time.time()) 237 y,m,d,H,M,S,x,x,x = time.gmtime(time.time())
228 238
243 # now handle the adjustment of hour 253 # now handle the adjustment of hour
244 ts = calendar.timegm((y,m,d,H,M,S,0,0,0)) 254 ts = calendar.timegm((y,m,d,H,M,S,0,0,0))
245 self.year, self.month, self.day, self.hour, self.minute, \ 255 self.year, self.month, self.day, self.hour, self.minute, \
246 self.second, x, x, x = time.gmtime(ts) 256 self.second, x, x, x = time.gmtime(ts)
247 257
248 if info['o']: 258 if info.get('o', None):
249 self.applyInterval(Interval(info['o'])) 259 self.applyInterval(Interval(info['o']))
250 260
251 def __repr__(self): 261 def __repr__(self):
252 return '<Date %s>'%self.__str__() 262 return '<Date %s>'%self.__str__()
253 263
259 self.second, x, x, x = time.gmtime(calendar.timegm(t)) 269 self.second, x, x, x = time.gmtime(calendar.timegm(t))
260 270
261 def get_tuple(self): 271 def get_tuple(self):
262 return (self.year, self.month, self.day, self.hour, self.minute, 272 return (self.year, self.month, self.day, self.hour, self.minute,
263 self.second, 0, 0, 0) 273 self.second, 0, 0, 0)
274
275 def serialise(self):
276 return '%4d%02d%02d%02d%02d%02d'%(self.year, self.month,
277 self.day, self.hour, self.minute, self.second)
264 278
265 class Interval: 279 class Interval:
266 ''' 280 '''
267 Date intervals are specified using the suffixes "y", "m", and "d". The 281 Date intervals are specified using the suffixes "y", "m", and "d". The
268 suffix "w" (for "week") means 7 days. Time intervals are specified in 282 suffix "w" (for "week") means 7 days. Time intervals are specified in
287 seconds, minutes, hours, years, months, days 301 seconds, minutes, hours, years, months, days
288 302
289 Calculations involving monts (eg '+2m') have no effect on days - only 303 Calculations involving monts (eg '+2m') have no effect on days - only
290 days (or over/underflow from hours/mins/secs) will do that, and 304 days (or over/underflow from hours/mins/secs) will do that, and
291 days-per-month and leap years are accounted for. Leap seconds are not. 305 days-per-month and leap years are accounted for. Leap seconds are not.
306
307 The interval format 'syyyymmddHHMMSS' (sign, year, month, day, hour,
308 minute, second) is the serialisation format returned by the serialise()
309 method, and is accepted as an argument on instatiation.
292 310
293 TODO: more examples, showing the order of addition operation 311 TODO: more examples, showing the order of addition operation
294 ''' 312 '''
295 def __init__(self, spec, sign=1): 313 def __init__(self, spec, sign=1):
296 """Construct an interval given a specification.""" 314 """Construct an interval given a specification."""
309 if not hasattr(other, attr): 327 if not hasattr(other, attr):
310 return 1 328 return 1
311 r = cmp(getattr(self, attr), getattr(other, attr)) 329 r = cmp(getattr(self, attr), getattr(other, attr))
312 if r: return r 330 if r: return r
313 return 0 331 return 0
314 332
315 def __str__(self): 333 def __str__(self):
316 """Return this interval as a string.""" 334 """Return this interval as a string."""
317 sign = {1:'+', -1:'-'}[self.sign] 335 sign = {1:'+', -1:'-'}[self.sign]
318 l = [sign] 336 l = [sign]
319 if self.year: l.append('%sy'%self.year) 337 if self.year: l.append('%sy'%self.year)
323 l.append('%d:%02d:%02d'%(self.hour, self.minute, self.second)) 341 l.append('%d:%02d:%02d'%(self.hour, self.minute, self.second))
324 elif self.hour or self.minute: 342 elif self.hour or self.minute:
325 l.append('%d:%02d'%(self.hour, self.minute)) 343 l.append('%d:%02d'%(self.hour, self.minute))
326 return ' '.join(l) 344 return ' '.join(l)
327 345
328 def set(self, spec, interval_re = re.compile(''' 346 def set(self, spec, interval_re=re.compile('''
329 \s* 347 \s*(?P<s>[-+])? # + or -
330 (?P<s>[-+])? # + or - 348 \s*((?P<y>\d+\s*)y)? # year
331 \s* 349 \s*((?P<m>\d+\s*)m)? # month
332 ((?P<y>\d+\s*)y)? # year 350 \s*((?P<w>\d+\s*)w)? # week
333 \s* 351 \s*((?P<d>\d+\s*)d)? # day
334 ((?P<m>\d+\s*)m)? # month 352 \s*(((?P<H>\d+):(?P<M>\d+))?(:(?P<S>\d+))?)? # time
335 \s* 353 \s*''', re.VERBOSE), serialised_re=re.compile('''
336 ((?P<w>\d+\s*)w)? # week 354 (?P<s>[+-])(?P<y>\d{4})(?P<m>\d{2})(?P<d>\d{2})
337 \s* 355 (?P<H>\d{2})(?P<M>\d{2})(?P<S>\d{2})''', re.VERBOSE)):
338 ((?P<d>\d+\s*)d)? # day
339 \s*
340 (((?P<H>\d+):(?P<M>\d+))?(:(?P<S>\d+))?)? # time
341 \s*
342 ''', re.VERBOSE)):
343 ''' set the date to the value in spec 356 ''' set the date to the value in spec
344 ''' 357 '''
345 self.year = self.month = self.week = self.day = self.hour = \ 358 self.year = self.month = self.week = self.day = self.hour = \
346 self.minute = self.second = 0 359 self.minute = self.second = 0
347 self.sign = 1 360 self.sign = 1
348 m = interval_re.match(spec) 361 m = serialised_re.match(spec)
349 if not m: 362 if not m:
350 raise ValueError, _('Not an interval spec: [+-] [#y] [#m] [#w] ' 363 m = interval_re.match(spec)
351 '[#d] [[[H]H:MM]:SS]') 364 if not m:
365 raise ValueError, _('Not an interval spec: [+-] [#y] [#m] [#w] '
366 '[#d] [[[H]H:MM]:SS]')
352 367
353 info = m.groupdict() 368 info = m.groupdict()
354 for group, attr in {'y':'year', 'm':'month', 'w':'week', 'd':'day', 369 for group, attr in {'y':'year', 'm':'month', 'w':'week', 'd':'day',
355 'H':'hour', 'M':'minute', 'S':'second'}.items(): 370 'H':'hour', 'M':'minute', 'S':'second'}.items():
356 if info[group] is not None: 371 if info.getr(group, None) is not None:
357 setattr(self, attr, int(info[group])) 372 setattr(self, attr, int(info[group]))
358 373
359 if self.week: 374 if self.week:
360 self.day = self.day + self.week*7 375 self.day = self.day + self.week*7
361 376
414 else: 429 else:
415 s = _('%(number)s/4 hour')%{'number': int(self.minute/15)} 430 s = _('%(number)s/4 hour')%{'number': int(self.minute/15)}
416 return s 431 return s
417 432
418 def get_tuple(self): 433 def get_tuple(self):
419 return (self.year, self.month, self.day, self.hour, self.minute, 434 return (self.sign, self.year, self.month, self.day, self.hour,
420 self.second) 435 self.minute, self.second)
436
437 def serialise(self):
438 return '%s%4d%02d%02d%02d%02d%02d'%(self.sign, self.year, self.month,
439 self.day, self.hour, self.minute, self.second)
421 440
422 441
423 def test(): 442 def test():
424 intervals = (" 3w 1 d 2:00", " + 2d", "3w") 443 intervals = (" 3w 1 d 2:00", " + 2d", "3w")
425 for interval in intervals: 444 for interval in intervals:
440 if __name__ == '__main__': 459 if __name__ == '__main__':
441 test() 460 test()
442 461
443 # 462 #
444 # $Log: not supported by cvs2svn $ 463 # $Log: not supported by cvs2svn $
464 # Revision 1.23 2002/07/18 23:07:08 richard
465 # Unit tests and a few fixes.
466 #
445 # Revision 1.22 2002/07/14 06:05:50 richard 467 # Revision 1.22 2002/07/14 06:05:50 richard
446 # . fixed the date module so that Date(". - 2d") works 468 # . fixed the date module so that Date(". - 2d") works
447 # 469 #
448 # Revision 1.21 2002/05/15 06:32:46 richard 470 # Revision 1.21 2002/05/15 06:32:46 richard
449 # . reverting to dates for intervals > 2 months sucks 471 # . reverting to dates for intervals > 2 months sucks

Roundup Issue Tracker: http://roundup-tracker.org/