| OLD | NEW | 
|---|
| 1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 1 # copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 
| 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 
| 3 # | 3 # | 
| 4 # This file is part of logilab-common. | 4 # This file is part of logilab-common. | 
| 5 # | 5 # | 
| 6 # logilab-common is free software: you can redistribute it and/or modify it unde
     r | 6 # logilab-common is free software: you can redistribute it and/or modify it unde
     r | 
| 7 # the terms of the GNU Lesser General Public License as published by the Free | 7 # the terms of the GNU Lesser General Public License as published by the Free | 
| 8 # Software Foundation, either version 2.1 of the License, or (at your option) an
     y | 8 # Software Foundation, either version 2.1 of the License, or (at your option) an
     y | 
| 9 # later version. | 9 # later version. | 
| 10 # | 10 # | 
| 11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT | 11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT | 
| 12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
| 13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more | 13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more | 
| 14 # details. | 14 # details. | 
| 15 # | 15 # | 
| 16 # You should have received a copy of the GNU Lesser General Public License along | 16 # You should have received a copy of the GNU Lesser General Public License along | 
| 17 # with logilab-common.  If not, see <http://www.gnu.org/licenses/>. | 17 # with logilab-common.  If not, see <http://www.gnu.org/licenses/>. | 
| 18 """Date manipulation helper functions.""" | 18 """Date manipulation helper functions.""" | 
| 19 from __future__ import division | 19 from __future__ import division | 
| 20 | 20 | 
| 21 __docformat__ = "restructuredtext en" | 21 __docformat__ = "restructuredtext en" | 
| 22 | 22 | 
| 23 import math | 23 import math | 
| 24 import re | 24 import re | 
| 25 from locale import getpreferredencoding | 25 import sys | 
|  | 26 from locale import getlocale, LC_TIME | 
| 26 from datetime import date, time, datetime, timedelta | 27 from datetime import date, time, datetime, timedelta | 
| 27 from time import strptime as time_strptime | 28 from time import strptime as time_strptime | 
| 28 from calendar import monthrange, timegm | 29 from calendar import monthrange, timegm | 
| 29 | 30 | 
|  | 31 from six.moves import range | 
|  | 32 | 
| 30 try: | 33 try: | 
| 31     from mx.DateTime import RelativeDateTime, Date, DateTimeType | 34     from mx.DateTime import RelativeDateTime, Date, DateTimeType | 
| 32 except ImportError: | 35 except ImportError: | 
| 33     endOfMonth = None | 36     endOfMonth = None | 
| 34     DateTimeType = datetime | 37     DateTimeType = datetime | 
| 35 else: | 38 else: | 
| 36     endOfMonth = RelativeDateTime(months=1, day=-1) | 39     endOfMonth = RelativeDateTime(months=1, day=-1) | 
| 37 | 40 | 
| 38 # NOTE: should we implement a compatibility layer between date representations | 41 # NOTE: should we implement a compatibility layer between date representations | 
| 39 #       as we have in lgc.db ? | 42 #       as we have in lgc.db ? | 
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 123         return delta.days | 126         return delta.days | 
| 124     else: | 127     else: | 
| 125         return int(math.ceil((end - start).days)) | 128         return int(math.ceil((end - start).days)) | 
| 126 | 129 | 
| 127 def get_national_holidays(begin, end): | 130 def get_national_holidays(begin, end): | 
| 128     """return french national days off between begin and end""" | 131     """return french national days off between begin and end""" | 
| 129     begin = datefactory(begin.year, begin.month, begin.day, begin) | 132     begin = datefactory(begin.year, begin.month, begin.day, begin) | 
| 130     end = datefactory(end.year, end.month, end.day, end) | 133     end = datefactory(end.year, end.month, end.day, end) | 
| 131     holidays = [str2date(datestr, begin) | 134     holidays = [str2date(datestr, begin) | 
| 132                 for datestr in FRENCH_MOBILE_HOLIDAYS.values()] | 135                 for datestr in FRENCH_MOBILE_HOLIDAYS.values()] | 
| 133     for year in xrange(begin.year, end.year+1): | 136     for year in range(begin.year, end.year+1): | 
| 134         for datestr in FRENCH_FIXED_HOLIDAYS.values(): | 137         for datestr in FRENCH_FIXED_HOLIDAYS.values(): | 
| 135             date = str2date(datestr % year, begin) | 138             date = str2date(datestr % year, begin) | 
| 136             if date not in holidays: | 139             if date not in holidays: | 
| 137                 holidays.append(date) | 140                 holidays.append(date) | 
| 138     return [day for day in holidays if begin <= day < end] | 141     return [day for day in holidays if begin <= day < end] | 
| 139 | 142 | 
| 140 def add_days_worked(start, days): | 143 def add_days_worked(start, days): | 
| 141     """adds date but try to only take days worked into account""" | 144     """adds date but try to only take days worked into account""" | 
| 142     step = get_step(start) | 145     step = get_step(start) | 
| 143     weeks, plus = divmod(days, 5) | 146     weeks, plus = divmod(days, 5) | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 180 | 183 | 
| 181     When using mx datetime, you should *NOT* use incmonth argument, use instead | 184     When using mx datetime, you should *NOT* use incmonth argument, use instead | 
| 182     oneDay, oneHour, oneMinute, oneSecond, oneWeek or endOfMonth (to enumerate | 185     oneDay, oneHour, oneMinute, oneSecond, oneWeek or endOfMonth (to enumerate | 
| 183     months) as `incday` argument | 186     months) as `incday` argument | 
| 184     """ | 187     """ | 
| 185     assert not (incday and incmonth) | 188     assert not (incday and incmonth) | 
| 186     begin = todate(begin) | 189     begin = todate(begin) | 
| 187     end = todate(end) | 190     end = todate(end) | 
| 188     if incmonth: | 191     if incmonth: | 
| 189         while begin < end: | 192         while begin < end: | 
|  | 193             yield begin | 
| 190             begin = next_month(begin, incmonth) | 194             begin = next_month(begin, incmonth) | 
| 191             yield begin |  | 
| 192     else: | 195     else: | 
| 193         incr = get_step(begin, incday or 1) | 196         incr = get_step(begin, incday or 1) | 
| 194         while begin < end: | 197         while begin < end: | 
| 195            yield begin | 198            yield begin | 
| 196            begin += incr | 199            begin += incr | 
| 197 | 200 | 
| 198 # makes py datetime usable ##################################################### | 201 # makes py datetime usable ##################################################### | 
| 199 | 202 | 
| 200 ONEDAY = timedelta(days=1) | 203 ONEDAY = timedelta(days=1) | 
| 201 ONEWEEK = timedelta(days=7) | 204 ONEWEEK = timedelta(days=7) | 
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 272     return somedate | 275     return somedate | 
| 273 | 276 | 
| 274 def first_day(somedate): | 277 def first_day(somedate): | 
| 275     return date(somedate.year, somedate.month, 1) | 278     return date(somedate.year, somedate.month, 1) | 
| 276 | 279 | 
| 277 def last_day(somedate): | 280 def last_day(somedate): | 
| 278     return date(somedate.year, somedate.month, days_in_month(somedate)) | 281     return date(somedate.year, somedate.month, days_in_month(somedate)) | 
| 279 | 282 | 
| 280 def ustrftime(somedate, fmt='%Y-%m-%d'): | 283 def ustrftime(somedate, fmt='%Y-%m-%d'): | 
| 281     """like strftime, but returns a unicode string instead of an encoded | 284     """like strftime, but returns a unicode string instead of an encoded | 
| 282     string which' may be problematic with localized date. | 285     string which may be problematic with localized date. | 
| 283 |  | 
| 284     encoding is guessed by locale.getpreferredencoding() |  | 
| 285     """ | 286     """ | 
| 286     encoding = getpreferredencoding(do_setlocale=False) or 'UTF-8' | 287     if sys.version_info >= (3, 3): | 
| 287     try: | 288         # datetime.date.strftime() supports dates since year 1 in Python >=3.3. | 
| 288         return unicode(somedate.strftime(str(fmt)), encoding) | 289         return somedate.strftime(fmt) | 
| 289     except ValueError, exc: | 290     else: | 
| 290         if somedate.year >= 1900: | 291         try: | 
| 291             raise | 292             if sys.version_info < (3, 0): | 
| 292         # datetime is not happy with dates before 1900 | 293                 encoding = getlocale(LC_TIME)[1] or 'ascii' | 
| 293         # we try to work around this, assuming a simple | 294                 return unicode(somedate.strftime(str(fmt)), encoding) | 
| 294         # format string | 295             else: | 
| 295         fields = {'Y': somedate.year, | 296                 return somedate.strftime(fmt) | 
| 296                   'm': somedate.month, | 297         except ValueError: | 
| 297                   'd': somedate.day, | 298             if somedate.year >= 1900: | 
| 298                   } | 299                 raise | 
| 299         if isinstance(somedate, datetime): | 300             # datetime is not happy with dates before 1900 | 
| 300             fields.update({'H': somedate.hour, | 301             # we try to work around this, assuming a simple | 
| 301                            'M': somedate.minute, | 302             # format string | 
| 302                            'S': somedate.second}) | 303             fields = {'Y': somedate.year, | 
| 303         fmt = re.sub('%([YmdHMS])', r'%(\1)02d', fmt) | 304                       'm': somedate.month, | 
| 304         return unicode(fmt) % fields | 305                       'd': somedate.day, | 
|  | 306                       } | 
|  | 307             if isinstance(somedate, datetime): | 
|  | 308                 fields.update({'H': somedate.hour, | 
|  | 309                                'M': somedate.minute, | 
|  | 310                                'S': somedate.second}) | 
|  | 311             fmt = re.sub('%([YmdHMS])', r'%(\1)02d', fmt) | 
|  | 312             return unicode(fmt) % fields | 
| 305 | 313 | 
| 306 def utcdatetime(dt): | 314 def utcdatetime(dt): | 
| 307     if dt.tzinfo is None: | 315     if dt.tzinfo is None: | 
| 308         return dt | 316         return dt | 
| 309     return datetime(*dt.utctimetuple()[:7]) | 317     return datetime(*dt.utctimetuple()[:7]) | 
| 310 | 318 | 
| 311 def utctime(dt): | 319 def utctime(dt): | 
| 312     if dt.tzinfo is None: | 320     if dt.tzinfo is None: | 
| 313         return dt | 321         return dt | 
| 314     return (dt + dt.utcoffset() + dt.dst()).replace(tzinfo=None) | 322     return (dt + dt.utcoffset() + dt.dst()).replace(tzinfo=None) | 
| 315 | 323 | 
| 316 def datetime_to_seconds(date): | 324 def datetime_to_seconds(date): | 
| 317     """return the number of seconds since the begining of the day for that date | 325     """return the number of seconds since the begining of the day for that date | 
| 318     """ | 326     """ | 
| 319     return date.second+60*date.minute + 3600*date.hour | 327     return date.second+60*date.minute + 3600*date.hour | 
| 320 | 328 | 
| 321 def timedelta_to_days(delta): | 329 def timedelta_to_days(delta): | 
| 322     """return the time delta as a number of seconds""" | 330     """return the time delta as a number of seconds""" | 
| 323     return delta.days + delta.seconds / (3600*24) | 331     return delta.days + delta.seconds / (3600*24) | 
| 324 | 332 | 
| 325 def timedelta_to_seconds(delta): | 333 def timedelta_to_seconds(delta): | 
| 326     """return the time delta as a fraction of days""" | 334     """return the time delta as a fraction of days""" | 
| 327     return delta.days*(3600*24) + delta.seconds | 335     return delta.days*(3600*24) + delta.seconds | 
| OLD | NEW | 
|---|