diff --git a/tryton/tryton/common/datetime_.py b/tryton/tryton/common/datetime_.py index 16b5731de3e..59dda93fd30 100644 --- a/tryton/tryton/common/datetime_.py +++ b/tryton/tryton/common/datetime_.py @@ -2,8 +2,8 @@ # this repository contains the full copyright notices and license terms. import datetime import gettext +import re -from dateutil.parser import parse from dateutil.relativedelta import relativedelta from gi.repository import Gdk, GObject, Gtk @@ -43,23 +43,56 @@ def _fix_format(format_): def date_parse(text, format_='%x'): - try: - return datetime.datetime.strptime(text, format_) - except ValueError: - pass - formatted_date = datetime.date(1988, 7, 16).strftime(format_) - try: - dayfirst = formatted_date.index('16') == 0 - except ValueError: - dayfirst = False - try: - monthfirst = formatted_date.index('7') <= 1 - except ValueError: - monthfirst = False - yearfirst = not dayfirst and not monthfirst - if len(text) == 8 and dayfirst: - return datetime.datetime.strptime(text, '%d%m%Y') - return parse(text, dayfirst=dayfirst, yearfirst=yearfirst, ignoretz=True) + def parse_date(text): + formatted_date = datetime.date(1988, 7, 16).strftime(format_) + try: + dayfirst = formatted_date.index('16') == 0 + except ValueError: + dayfirst = False + try: + monthfirst = formatted_date.index('7') <= 1 + except ValueError: + monthfirst = False + + text = re.sub('[^0-9]', '', text) + if len(text) not in {6, 8}: + raise ValueError + + year_format = '%Y' if len(text) == 8 else '%y' + if dayfirst: + parse_format = '%d%m' + year_format + elif monthfirst: + parse_format = '%m%d' + year_format + else: + # Probably ISO otherwise it's very strange + parse_format = year_format + '%m%d' + + return datetime.datetime.strptime(text, parse_format).date() + + def parse_time(text): + h, m, *s = text.split(':', 2) + if s: + if '.' in s[0]: + s, us = s[0].split('.') + else: + s, us = s[0], None + else: + s, us = None, None + return datetime.time( + int(h), int(m), int(s) if s else 0, + int(us) if us else 0) + + date, time = None, None + if ' ' in text: + date, time = text.split(' ', 1) + elif ':' in text: + time = text + else: + date = text + + date = parse_date(date) if date else datetime.date.today() + time = parse_time(time) if time else datetime.time() + return datetime.datetime.combine(date, time) class Date(Gtk.Entry): diff --git a/tryton/tryton/gui/window/view_form/model/field.py b/tryton/tryton/gui/window/view_form/model/field.py index 1eddcfc2f4f..d9d3502bab9 100644 --- a/tryton/tryton/gui/window/view_form/model/field.py +++ b/tryton/tryton/gui/window/view_form/model/field.py @@ -301,6 +301,8 @@ def set_client(self, record, value, force_change=False): current_value.date(), value) else: value = None + elif value is INVALID_DT_VALUE: + pass elif value and not isinstance(value, datetime.datetime): current_value = self.get_client(record) if current_value: @@ -308,13 +310,15 @@ def set_client(self, record, value, force_change=False): else: time = datetime.time() value = datetime.datetime.combine(value, time) - if value: + if value and value is not INVALID_DT_VALUE: value = common.untimezoned_date(value) super(DateTimeField, self).set_client(record, value, force_change=force_change) def get_client(self, record): value = super(DateTimeField, self).get_client(record) + if value is INVALID_DT_VALUE: + return value if value: return common.timezoned_date(value)