Change most Date fields by DateTime

Continuing the discussion from Pending State on Purchase Requests:
We usually use a date field to store the “date” (in speaking language) of the record but it is because we are thinking only about simple case (like sale date, stock move date etc.). If we want to make Tryton ready for more use-cases where the precision should be smaller than the day, we should use DateTime fields.
The idea is to replace those dates by a DateTime with by default no format for the time part like that it is transparent to the user (and the developer).
The opened question is how to deal with time-zone in this perspective because DateTime are stored in UTC?

We had to implement a simple module[1] to get date and time in stock moves and shipments (for now only internal and out).
Generally we had no problem with UTC and time-zone conversion due to client converts pretty well the values, but there are some points which must be remark:

  • CSV exporting does not convert UTC date time to user time zone.
  • At programming level it’s difficult to deal with date and date time fields without information about user time zone. In our case (Spain), querying by standard way the stock of a product at a date will not return a correct stock if some movements where created by user with no time (they are saved in UTC, so the day/date stored is yesterday at 23:00:00).

IMHO user time zone could be cached in context, and ‘ir.date’ model could have a method to convert from TZ to UTC and viceversa.

[1] https://bitbucket.org/datalife_sco/trytond-stock_move_time

I think it is probably better when the need exists to just replace the date fields by datetime fields via a module. Normally now, most operation done on those dates are using DeltaTime which will work transparently for both type.
Of course such module should be carefully tested to ensure that no operation relies on the Date only feature. I think for example about code that compare with today which should probably convert to date in case (ex: Move.compute_quantities_query).

In case of using datetime shouldn’t the value be now instead of today?

Yes of course, this should be part of the extension module.
And even maybe it should have a configuration (ex: on warehouse) to pick a default time.

I’ve developed a module that changes the date field of account payment into a datetime field.

Here is the code needed to implement such change:

@classmethod                                                               
def __setup__(cls):                                                                                      
    super(Payment, cls).__setup__()                          
    # Override definition to change Date to DateTime                       
    cls.date = fields.DateTime(cls.date.string, help=cls.date.help,        
        required=cls.date.required)              
                                                                           
@classmethod                                                               
def default_date(cls):                                                     
    date = super(Payment, cls).default_date()                              
    return datetime.datetime.combine(date, datetime.datetime.now().time()) 
                                                                           
@classmethod                                                               
def _view_look_dom_arch(cls, tree, type, field_children=None):             
    # Override date field to use date widget on list                       
    if type == 'tree':                                                     
        elements = tree.xpath('//field[@name="date"]')                     
        for field in elements:                                             
            field.attrib['widget'] = 'date'                                
    return super(Payment, cls)._view_look_dom_arch(                        
        tree, type, field_children)

The only drawback that we found is that this breaks the sqlite as alter type is not suported by sqlite.

1 Like

Indeed it’s a missing feature for sqlite. Opened issue6730 in order to support it on newer versions.

Why using __post_setup__ instead of __setup__? It is not supposed to be for public usage.

My fault, using __setup__ works, but you have to redifine the field after the super call. I’m updating the code snippet.

Thanks for your feedback.