diff options
| author | Raphael Collet <rco@odoo.com> | 2018-08-06 14:37:19 +0200 |
|---|---|---|
| committer | Adrian Torres <adt@odoo.com> | 2018-08-06 14:37:19 +0200 |
| commit | 960360afe478a8f7b9c456721b5591154952a37d (patch) | |
| tree | a01a68e1ac059d243755c24311d4560722625002 /odoo/tools/date_utils.py | |
| parent | 09ba95b2d06760d7486ebb587af2099cccb8955f (diff) | |
[REF] *: use native date/datetime for Date/Datetime fields
From this commit onwards, Date fields will return datetime.date objects and Datetime fields will return datetime.datetime objects, this implies a number of things that are clearly explained both in the ORM API for master.
This commit also introduces a number of helper functions for dates and datetimes that are exposed in tools.date_utils and fields.Date[time], explained in the documentation as well.
Task-ID: 47189
Diffstat (limited to 'odoo/tools/date_utils.py')
| -rw-r--r-- | odoo/tools/date_utils.py | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/odoo/tools/date_utils.py b/odoo/tools/date_utils.py index 76b19c2cf55..e7d1aa24ffd 100644 --- a/odoo/tools/date_utils.py +++ b/odoo/tools/date_utils.py @@ -2,8 +2,10 @@ import math import calendar +from datetime import date, datetime, time from dateutil.relativedelta import relativedelta +from . import ustr def get_month(date): @@ -62,3 +64,117 @@ def get_fiscal_year(date, day=31, month=12): max_day = calendar.monthrange(date_to.year + 1, date_to.month)[1] date_to = type(date)(date.year + 1, month, min(day, max_day)) return date_from, date_to + + +def start_of(value, granularity): + """ + Get start of a time period from a date or a datetime. + + :param value: initial date or datetime. + :param granularity: type of period in string, can be year, quarter, month, week, day or hour. + :return: a date/datetime object corresponding to the start of the specified period. + """ + is_datetime = isinstance(value, datetime) + if granularity == "year": + result = value.replace(month=1, day=1) + elif granularity == "quarter": + # Q1 = Jan 1st + # Q2 = Apr 1st + # Q3 = Jul 1st + # Q4 = Oct 1st + result = get_quarter(value)[0] + elif granularity == "month": + result = value.replace(day=1) + elif granularity == 'week': + # `calendar.weekday` uses ISO8601 for start of week reference, this means that + # by default MONDAY is the first day of the week and SUNDAY is the last. + result = value - relativedelta(days=calendar.weekday(value.year, value.month, value.day)) + elif granularity == "day": + result = value + elif granularity == "hour" and is_datetime: + return datetime.combine(value, time.min).replace(hour=value.hour) + elif is_datetime: + raise ValueError( + "Granularity must be year, quarter, month, week, day or hour for value %s" % value + ) + else: + raise ValueError( + "Granularity must be year, quarter, month, week or day for value %s" % value + ) + + return datetime.combine(result, time.min) if is_datetime else result + + +def end_of(value, granularity): + """ + Get end of a time period from a date or a datetime. + + :param value: initial date or datetime. + :param granularity: Type of period in string, can be year, quarter, month, week, day or hour. + :return: A date/datetime object corresponding to the start of the specified period. + """ + is_datetime = isinstance(value, datetime) + if granularity == "year": + result = value.replace(month=12, day=31) + elif granularity == "quarter": + # Q1 = Mar 31st + # Q2 = Jun 30th + # Q3 = Sep 30th + # Q4 = Dec 31st + result = get_quarter(value)[1] + elif granularity == "month": + result = value + relativedelta(day=1, months=1, days=-1) + elif granularity == 'week': + # `calendar.weekday` uses ISO8601 for start of week reference, this means that + # by default MONDAY is the first day of the week and SUNDAY is the last. + result = value + relativedelta(days=6-calendar.weekday(value.year, value.month, value.day)) + elif granularity == "day": + result = value + elif granularity == "hour" and is_datetime: + return datetime.combine(value, time.max).replace(hour=value.hour) + elif is_datetime: + raise ValueError( + "Granularity must be year, quarter, month, week, day or hour for value %s" % value + ) + else: + raise ValueError( + "Granularity must be year, quarter, month, week or day for value %s" % value + ) + + return datetime.combine(result, time.max) if is_datetime else result + + +def add(value, *args, **kwargs): + """ + Return the sum of ``value`` and a :class:`relativedelta`. + + :param value: initial date or datetime. + :param args: positional args to pass directly to :class:`relativedelta`. + :param kwargs: keyword args to pass directly to :class:`relativedelta`. + :return: the resulting date/datetime. + """ + return value + relativedelta(*args, **kwargs) + + +def subtract(value, *args, **kwargs): + """ + Return the difference between ``value`` and a :class:`relativedelta`. + + :param value: initial date or datetime. + :param args: positional args to pass directly to :class:`relativedelta`. + :param kwargs: keyword args to pass directly to :class:`relativedelta`. + :return: the resulting date/datetime. + """ + return value - relativedelta(*args, **kwargs) + + +def json_default(obj): + """ + Properly serializes date and datetime objects. + """ + from odoo import fields + if isinstance(obj, date): + if isinstance(obj, datetime): + return fields.Datetime.to_string(obj) + return fields.Date.to_string(obj) + return ustr(obj) |
