summaryrefslogtreecommitdiff
path: root/logilab/common/date.py
diff options
context:
space:
mode:
Diffstat (limited to 'logilab/common/date.py')
-rw-r--r--logilab/common/date.py53
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: