utils.py
branchtls-sprint
changeset 1715 cba9f175da2d
parent 1711 182536159750
child 1751 59e9a4f5bfea
--- a/utils.py	Thu May 07 16:33:22 2009 +0200
+++ b/utils.py	Thu May 07 16:42:34 2009 +0200
@@ -11,10 +11,10 @@
 from datetime import datetime, timedelta, date
 from time import time
 from random import randint, seed
-    
+from calendar import monthrange
+
 # initialize random seed from current time
 seed()
-
 try:
     strptime = datetime.strptime
 except AttributeError: # py < 2.5
@@ -26,29 +26,70 @@
     """return a date from a date (leaving unchanged) or a datetime"""
     if isinstance(somedate, datetime):
         return date(somedate.year, somedate.month, somedate.day)
-    assert isinstance(somedate, date)
-    return date
+    assert isinstance(somedate, date), repr(somedate)
+    return somedate
+
+def todatetime(somedate):
+    """return a date from a date (leaving unchanged) or a datetime"""
+    if isinstance(somedate, date):
+        return datetime(somedate.year, somedate.month, somedate.day)
+    assert isinstance(somedate, datetime), repr(somedate)
+    return somedate
+
+ONEDAY = timedelta(days=1)
+ONEWEEK = timedelta(days=7)
+
+def days_in_month(date_):
+    return monthrange(date_.year, date_.month)[1]
 
-def date_range(begin, end, incr=1, include=None):
+def previous_month(date_, nbmonth=1):
+    while nbmonth:
+        date_ = first_day(date_) - ONEDAY
+        nbmonth -= 1
+    return date_
+
+def next_month(date_, nbmonth=1):
+    while nbmonth:
+        date_ = last_day(date_) + ONEDAY
+        nbmonth -= 1
+    return date_
+
+def first_day(date_):
+    return date(date_.year, date_.month, 1)
+
+def last_day(date_):
+    return date(date_.year, date_.month, days_in_month(date_))
+
+def date_range(begin, end, incday=None, incmonth=None):
     """yields each date between begin and end
     :param begin: the start date
     :param end: the end date
     :param incr: the step to use to iterate over dates. Default is
-                 one day.                 
+                 one day.
     :param include: None (means no exclusion) or a function taking a
                     date as parameter, and returning True if the date
                     should be included.
     """
-    incr = timedelta(incr, 0, 0)
-    while begin <= end:
-        if include is None or include(begin): 
+    assert not (incday and incmonth)
+    begin = todate(begin)
+    end = todate(end)
+    if incmonth:
+        while begin < end:
+            begin = next_month(begin, incmonth)
             yield begin
-        begin += incr
+    else:
+        if not incday:
+            incr = ONEDAY
+        else:
+            incr = timedelta(incday)
+        while begin <= end:
+           yield begin
+           begin += incr
 
 def ustrftime(date, fmt='%Y-%m-%d'):
     """like strftime, but returns a unicode string instead of an encoded
-    string which may be problematic with localized date.
-    
+    string which' may be problematic with localized date.
+
     encoding is guessed by locale.getpreferredencoding()
     """
     # date format may depend on the locale
@@ -79,7 +120,7 @@
     dict1 = dict(dict1)
     dict1.update(dict2)
     return dict1
-                
+
 
 class SizeConstrainedList(list):
     """simple list that makes sure the list does not get bigger
@@ -120,12 +161,12 @@
 
     def __nonzero__(self):
         return True
-    
+
     def write(self, value):
         assert isinstance(value, unicode), u"unicode required not %s : %s"\
                                      % (type(value).__name__, repr(value))
         self.append(value)
-        
+
     def getvalue(self):
         return u''.join(self)
 
@@ -164,8 +205,8 @@
         self.add_post_inline_script(u"""jQuery(document).ready(function () {
  %s
  });""" % jscode)
-        
-    
+
+
     def add_js(self, jsfile):
         """adds `jsfile` to the list of javascripts used in the webpage
 
@@ -231,18 +272,18 @@
         if skiphead:
             return header
         return u'<head>\n%s</head>\n' % header
-        
+
 
 class HTMLStream(object):
     """represents a HTML page.
 
     This is used my main templates so that HTML headers can be added
     at any time during the page generation.
-    
+
     HTMLStream uses the (U)StringIO interface to be compliant with
     existing code.
     """
-    
+
     def __init__(self, req):
         # stream for <head>
         self.head = req.html_headers