From 4a40db209706a5adae879a2b4349f873b336ccb9 Mon Sep 17 00:00:00 2001 From: Francois Volral Date: Mon, 9 Jul 2018 14:46:45 +0200 Subject: [IMP] orm: add support to fill temporal holes (read_group) This commit add an extra parameter 'fill_temporal' to read_group which allows the orm to add missing groups for date intervals. This is useful for charts. Suppose that we are in a use case where data are grouped by a date fields (typically months but it could be another interval) and displayed in a Bar Chart or a Line Char. Let's says a request has to group records by month for August, September and ...December. If we don't changed anything, we would get a Bar Chart looking like this : ___ ___ | | | | | | | | ___ | | | || || | |___||___||___| Aug Sep D December follows directly after September, it can be unintuitive for the user, so we change that. We add some fake records for each missing months between the earliest and the lastest date of the result ___ ___ | | | | | | | | ___ | | | || | | | |___||___| ___ ___ |___| Aug Sep Oct Nov Dec This commit is part of task #1835644 --- odoo/tools/date_utils.py | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) (limited to 'odoo/tools/date_utils.py') diff --git a/odoo/tools/date_utils.py b/odoo/tools/date_utils.py index e7d1aa24ffd..55220ced033 100644 --- a/odoo/tools/date_utils.py +++ b/odoo/tools/date_utils.py @@ -1,9 +1,8 @@ # -*- coding: utf-8 -*- - import math import calendar from datetime import date, datetime, time - +import pytz from dateutil.relativedelta import relativedelta from . import ustr @@ -178,3 +177,43 @@ def json_default(obj): return fields.Datetime.to_string(obj) return fields.Date.to_string(obj) return ustr(obj) + +def date_range(start, end, step=relativedelta(months=1)): + """Date range generator with a step interval. + + :param start datetime: begining date of the range. + :param end datetime: ending date of the range. + :param step relativedelta: interval of the range. + :return: a range of datetime from start to end. + :rtype: Iterator[datetime] + """ + + are_naive = start.tzinfo is None and end.tzinfo is None + are_utc = start.tzinfo == pytz.utc and end.tzinfo == pytz.utc + + # Cases with miscellenous timezone are more complexe because of DST. + are_others = start.tzinfo and end.tzinfo and not are_utc + + if are_others: + if start.tzinfo.zone != end.tzinfo.zone: + raise ValueError("Timezones of start argument and end argument seem inconsistent") + + if not are_naive and not are_utc and not are_others: + raise ValueError("Timezones of start argument and end argument mismatch") + + if start > end: + raise ValueError("start > end, start date must be before end") + + if start == start + step: + raise ValueError("Looks like step is null") + + if start.tzinfo: + localize = start.tzinfo.localize + else: + localize = lambda dt: dt + + dt = start.replace(tzinfo=None) + end = end.replace(tzinfo=None) + while dt <= end: + yield localize(dt) + dt = dt + step -- cgit v1.2.3