diff options
Diffstat (limited to 'logilab/common/date.py')
-rw-r--r-- | logilab/common/date.py | 53 |
1 files changed, 30 insertions, 23 deletions
diff --git a/logilab/common/date.py b/logilab/common/date.py index cdf2317..2d2ed22 100644 --- a/logilab/common/date.py +++ b/logilab/common/date.py @@ -27,6 +27,8 @@ from locale import getlocale, LC_TIME from datetime import date, time, datetime, timedelta from time import strptime as time_strptime from calendar import monthrange, timegm +from typing import Union, List, Any, Iterator, Optional, Generator + try: from mx.DateTime import RelativeDateTime, Date, DateTimeType @@ -90,13 +92,13 @@ FRENCH_MOBILE_HOLIDAYS = { # XXX this implementation cries for multimethod dispatching -def get_step(dateobj, nbdays=1): +def get_step(dateobj: Union[date, datetime], nbdays: int = 1) -> timedelta: # assume date is either a python datetime or a mx.DateTime object if isinstance(dateobj, date): return ONEDAY * nbdays return nbdays # mx.DateTime is ok with integers -def datefactory(year, month, day, sampledate): +def datefactory(year: int, month: int, day: int, sampledate: Union[date, datetime]) -> Union[date, datetime]: # assume date is either a python datetime or a mx.DateTime object if isinstance(sampledate, datetime): return datetime(year, month, day) @@ -104,20 +106,23 @@ def datefactory(year, month, day, sampledate): return date(year, month, day) return Date(year, month, day) -def weekday(dateobj): +def weekday(dateobj: Union[date, datetime]) -> int: # assume date is either a python datetime or a mx.DateTime object if isinstance(dateobj, date): return dateobj.weekday() return dateobj.day_of_week -def str2date(datestr, sampledate): +def str2date(datestr: str, sampledate: Union[date, datetime]) -> Union[date, datetime]: # NOTE: datetime.strptime is not an option until we drop py2.4 compat year, month, day = [int(chunk) for chunk in datestr.split('-')] return datefactory(year, month, day, sampledate) -def days_between(start, end): +def days_between(start: Union[date, datetime], end: Union[date, datetime]) -> int: if isinstance(start, date): - delta = end - start + # mypy: No overload variant of "__sub__" of "datetime" matches argument type "date" + # we ensure that end is a date + assert isinstance(end, date) + delta = end - start # type: ignore # datetime.timedelta.days is always an integer (floored) if delta.seconds: return delta.days + 1 @@ -125,7 +130,7 @@ def days_between(start, end): else: return int(math.ceil((end - start).days)) -def get_national_holidays(begin, end): +def get_national_holidays(begin: Union[date, datetime], end: Union[date, datetime]) -> Union[List[date], List[datetime]]: """return french national days off between begin and end""" begin = datefactory(begin.year, begin.month, begin.day, begin) end = datefactory(end.year, end.month, end.day, end) @@ -138,7 +143,7 @@ def get_national_holidays(begin, end): holidays.append(date) return [day for day in holidays if begin <= day < end] -def add_days_worked(start, days): +def add_days_worked(start: date, days: int) -> date: """adds date but try to only take days worked into account""" step = get_step(start) weeks, plus = divmod(days, 5) @@ -151,7 +156,7 @@ def add_days_worked(start, days): end += (2 * step) return end -def nb_open_days(start, end): +def nb_open_days(start: Union[date, datetime], end: Union[date, datetime]) -> int: assert start <= end step = get_step(start) days = days_between(start, end) @@ -168,7 +173,8 @@ def nb_open_days(start, end): return 0 return open_days -def date_range(begin, end, incday=None, incmonth=None): + +def date_range(begin: date, end: date, incday: Optional[Any] = None, incmonth: Optional[bool] = None) -> Generator[date, Any, None]: """yields each date between begin and end :param begin: the start date @@ -193,13 +199,13 @@ def date_range(begin, end, incday=None, incmonth=None): else: incr = get_step(begin, incday or 1) while begin < end: - yield begin - begin += incr + yield begin + begin += incr # makes py datetime usable ##################################################### -ONEDAY = timedelta(days=1) -ONEWEEK = timedelta(days=7) +ONEDAY: timedelta = timedelta(days=1) +ONEWEEK: timedelta = timedelta(days=7) try: strptime = datetime.strptime @@ -211,7 +217,7 @@ except AttributeError: # py < 2.5 def strptime_time(value, format='%H:%M'): return time(*time_strptime(value, format)[3:6]) -def todate(somedate): +def todate(somedate: date) -> date: """return a date from a date (leaving unchanged) or a datetime""" if isinstance(somedate, datetime): return date(somedate.year, somedate.month, somedate.day) @@ -234,10 +240,10 @@ def todatetime(somedate): assert isinstance(somedate, (date, DateTimeType)), repr(somedate) return datetime(somedate.year, somedate.month, somedate.day) -def datetime2ticks(somedate): +def datetime2ticks(somedate: Union[date, datetime]) -> int: return timegm(somedate.timetuple()) * 1000 + int(getattr(somedate, 'microsecond', 0) / 1000) -def ticks2datetime(ticks): +def ticks2datetime(ticks: int) -> datetime: miliseconds, microseconds = divmod(ticks, 1000) try: return datetime.fromtimestamp(miliseconds) @@ -250,7 +256,7 @@ def ticks2datetime(ticks): except (ValueError, OverflowError): raise -def days_in_month(somedate): +def days_in_month(somedate: date) -> int: return monthrange(somedate.year, somedate.month)[1] def days_in_year(somedate): @@ -266,7 +272,7 @@ def previous_month(somedate, nbmonth=1): nbmonth -= 1 return somedate -def next_month(somedate, nbmonth=1): +def next_month(somedate: date, nbmonth: int = 1) -> date: while nbmonth: somedate = last_day(somedate) + ONEDAY nbmonth -= 1 @@ -275,10 +281,10 @@ def next_month(somedate, nbmonth=1): def first_day(somedate): return date(somedate.year, somedate.month, 1) -def last_day(somedate): +def last_day(somedate: date) -> date: return date(somedate.year, somedate.month, days_in_month(somedate)) -def ustrftime(somedate, fmt='%Y-%m-%d'): +def ustrftime(somedate: datetime, fmt: str = '%Y-%m-%d') -> str: """like strftime, but returns a unicode string instead of an encoded string which may be problematic with localized date. """ @@ -309,10 +315,11 @@ def ustrftime(somedate, fmt='%Y-%m-%d'): fmt = re.sub('%([YmdHMS])', r'%(\1)02d', fmt) return unicode(fmt) % fields -def utcdatetime(dt): +def utcdatetime(dt: datetime) -> datetime: if dt.tzinfo is None: return dt - return (dt.replace(tzinfo=None) - dt.utcoffset()) + # mypy: No overload variant of "__sub__" of "datetime" matches argument type "None" + return (dt.replace(tzinfo=None) - dt.utcoffset()) # type: ignore def utctime(dt): if dt.tzinfo is None: |