From 10345423b16f2a16c43fda671024e6f793eb7c1b Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 9 Oct 2012 10:54:46 +0200 Subject: [PATCH] [FIX] treat imported datetime as local to the context-provided or user's datetime bzr revid: xmo@openerp.com-20121009085446-obfpn4c5r250zonc --- openerp/addons/base/ir/ir_fields.py | 38 +++++++++++-- .../addons/test_impex/tests/test_load.py | 53 ++++++++++++++++++- 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/openerp/addons/base/ir/ir_fields.py b/openerp/addons/base/ir/ir_fields.py index 1c14fdb3c4d..94a0be9e86c 100644 --- a/openerp/addons/base/ir/ir_fields.py +++ b/openerp/addons/base/ir/ir_fields.py @@ -1,10 +1,14 @@ # -*- coding: utf-8 -*- +import datetime import functools import operator import itertools -import psycopg2 import time -from openerp.osv import orm, fields + +import psycopg2 +import pytz + +from openerp.osv import orm from openerp.tools.translate import _ from openerp.tools.misc import DEFAULT_SERVER_DATE_FORMAT,\ DEFAULT_SERVER_DATETIME_FORMAT @@ -131,16 +135,42 @@ class ir_fields_converter(orm.Model): 'moreinfo': _(u"Use the format '%s'") % u"2012-12-31" }) + def _input_tz(self, cr, uid, context): + # if there's a tz in context, try to use that + if context.get('tz'): + try: + return pytz.timezone(context['tz']) + except pytz.UnknownTimeZoneError: + pass + + # if the current user has a tz set, try to use that + user = self.pool['res.users'].read( + cr, uid, [uid], ['tz'], context=context)[0] + if user['tz']: + try: + return pytz.timezone(user['tz']) + except pytz.UnknownTimeZoneError: + pass + + # fallback if no tz in context or on user: UTC + return pytz.UTC + def _str_to_datetime(self, cr, uid, model, column, value, context=None): + if context is None: context = {} try: - time.strptime(value, DEFAULT_SERVER_DATETIME_FORMAT) - return value, [] + parsed_value = datetime.datetime.strptime( + value, DEFAULT_SERVER_DATETIME_FORMAT) except ValueError: raise ValueError( _(u"'%s' does not seem to be a valid datetime for field '%%(field)s'") % value, { 'moreinfo': _(u"Use the format '%s'") % u"2012-12-31 23:59:59" }) + input_tz = self._input_tz(cr, uid, context)# Apply input tz to the parsed naive datetime + dt = input_tz.localize(parsed_value, is_dst=False) + # And convert to UTC before reformatting for writing + return dt.astimezone(pytz.UTC).strftime(DEFAULT_SERVER_DATETIME_FORMAT), [] + def _get_translations(self, cr, uid, types, src, context): types = tuple(types) # Cache translations so they don't have to be reloaded from scratch on diff --git a/openerp/tests/addons/test_impex/tests/test_load.py b/openerp/tests/addons/test_impex/tests/test_load.py index 18958969dfb..043337dd027 100644 --- a/openerp/tests/addons/test_impex/tests/test_load.py +++ b/openerp/tests/addons/test_impex/tests/test_load.py @@ -1039,5 +1039,54 @@ class test_datetime(ImporterCase): moreinfo=u"Use the format '2012-12-31 23:59:59'")]) self.assertIs(result['ids'], False) -# function, related, reference: written to db as-is... -# => function uses @type for value coercion/conversion + def test_checktz1(self): + """ Imported date should be interpreted as being in the tz provided by + the context + """ + # write dummy tz in user (Asia/Hovd UTC+0700), should be superseded by + # context + self.registry('res.users').write( + self.cr, openerp.SUPERUSER_ID, [openerp.SUPERUSER_ID], + {'tz': 'Asia/Hovd'}) + + # UTC+1400 + result = self.import_( + ['value'], [['2012-02-03 11:11:11']], {'tz': 'Pacific/Kiritimati'}) + self.assertFalse(result['messages']) + self.assertEqual( + values(self.read(domain=[('id', 'in', result['ids'])])), + ['2012-02-02 21:11:11']) + + # UTC-0930 + result = self.import_( + ['value'], [['2012-02-03 11:11:11']], {'tz': 'Pacific/Marquesas'}) + self.assertFalse(result['messages']) + self.assertEqual( + values(self.read(domain=[('id', 'in', result['ids'])])), + ['2012-02-03 20:41:11']) + + def test_usertz(self): + """ If the context does not hold a timezone, the importing user's tz + should be used + """ + # UTC +1000 + self.registry('res.users').write( + self.cr, openerp.SUPERUSER_ID, [openerp.SUPERUSER_ID], + {'tz': 'Asia/Yakutsk'}) + + result = self.import_( + ['value'], [['2012-02-03 11:11:11']]) + self.assertFalse(result['messages']) + self.assertEqual( + values(self.read(domain=[('id', '=', result['ids'])])), + ['2012-02-03 01:11:11']) + + def test_notz(self): + """ If there is no tz either in the context or on the user, falls back + to UTC + """ + result = self.import_(['value'], [['2012-02-03 11:11:11']]) + self.assertFalse(result['messages']) + self.assertEqual( + values(self.read(domain=[('id', '=', result['ids'])])), + ['2012-02-03 11:11:11'])