# HG changeset patch # User Sylvain Thénault # Date 1450427003 -3600 # Node ID 63d860a14a170d47502e153362c2abb9c0d574fe # Parent 38afb7e23c6ca1293548e5cf8ecf923d3a5a2082 [schema] Use TZDatetime for creation_date and modification_date No work has been done for form fields/widgets since creation_date / modification_date are by default not editable through the default UI. One may want to add such feature at some point. Time will be displayed as UTC, let the end-application decide otherwise by customizing the tzdatetime printer if desired. Closes #4848923 diff -r 38afb7e23c6c -r 63d860a14a17 dataimport/massive_store.py --- a/dataimport/massive_store.py Fri Dec 18 09:37:15 2015 +0100 +++ b/dataimport/massive_store.py Fri Dec 18 09:23:23 2015 +0100 @@ -119,7 +119,7 @@ self._dbh = PGHelper(self._cnx, pg_schema) self._data_entities = defaultdict(list) self._data_relations = defaultdict(list) - self._now = datetime.now() + self._now = datetime.utcnow() self._default_cwuri = make_uid('_auto_generated') self._count_cwuri = 0 self.on_commit_callback = on_commit_callback diff -r 38afb7e23c6c -r 63d860a14a17 dataimport/stores.py --- a/dataimport/stores.py Fri Dec 18 09:37:15 2015 +0100 +++ b/dataimport/stores.py Fri Dec 18 09:23:23 2015 +0100 @@ -259,7 +259,7 @@ source = cnx.repo.system_source self.source = source self.create_eid = cnx.repo.system_source.create_eid - self.time = datetime.now() + self.time = datetime.utcnow() # attributes/relations shared by all entities of the same type self.etype_attrs = [] self.etype_rels = [] diff -r 38afb7e23c6c -r 63d860a14a17 dataimport/test/test_stores.py --- a/dataimport/test/test_stores.py Fri Dec 18 09:37:15 2015 +0100 +++ b/dataimport/test/test_stores.py Fri Dec 18 09:23:23 2015 +0100 @@ -75,7 +75,7 @@ metagen = stores.MetaGenerator(cnx) # hijack gen_modification_date to ensure we don't go through it metagen.gen_modification_date = None - md = DT.datetime.now() - DT.timedelta(days=1) + md = DT.datetime.utcnow() - DT.timedelta(days=1) entity, rels = metagen.base_etype_dicts('CWUser') entity.cw_edited.update(dict(modification_date=md)) with cnx.ensure_cnx_set: diff -r 38afb7e23c6c -r 63d860a14a17 hooks/metadata.py --- a/hooks/metadata.py Fri Dec 18 09:37:15 2015 +0100 +++ b/hooks/metadata.py Fri Dec 18 09:23:23 2015 +0100 @@ -41,7 +41,7 @@ events = ('before_add_entity',) def __call__(self): - timestamp = datetime.now() + timestamp = datetime.utcnow() edited = self.entity.cw_edited if not edited.get('creation_date'): edited['creation_date'] = timestamp @@ -64,7 +64,7 @@ # XXX to be really clean, we should turn off modification_date update # explicitly on each command where we do not want that behaviour. if not self._cw.vreg.config.repairing: - self.entity.cw_edited.setdefault('modification_date', datetime.now()) + self.entity.cw_edited.setdefault('modification_date', datetime.utcnow()) class SetCreatorOp(hook.DataOperationMixIn, hook.Operation): diff -r 38afb7e23c6c -r 63d860a14a17 hooks/test/unittest_hooks.py --- a/hooks/test/unittest_hooks.py Fri Dec 18 09:37:15 2015 +0100 +++ b/hooks/test/unittest_hooks.py Fri Dec 18 09:23:23 2015 +0100 @@ -115,7 +115,7 @@ def test_metadata_creation_modification_date(self): with self.admin_access.repo_cnx() as cnx: - _now = datetime.now() + _now = datetime.utcnow() entity = cnx.create_entity('Workflow', name=u'wf1') self.assertEqual((entity.creation_date - _now).seconds, 0) self.assertEqual((entity.modification_date - _now).seconds, 0) diff -r 38afb7e23c6c -r 63d860a14a17 hooks/workflow.py --- a/hooks/workflow.py Fri Dec 18 09:37:15 2015 +0100 +++ b/hooks/workflow.py Fri Dec 18 09:23:23 2015 +0100 @@ -320,7 +320,7 @@ return entity = self._cw.entity_from_eid(self.eidfrom) try: - entity.cw_set(modification_date=datetime.now()) + entity.cw_set(modification_date=datetime.utcnow()) except RepositoryError as ex: # usually occurs if entity is coming from a read-only source # (eg ldap user) diff -r 38afb7e23c6c -r 63d860a14a17 misc/migration/3.22.0_Any.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/migration/3.22.0_Any.py Fri Dec 18 09:23:23 2015 +0100 @@ -0,0 +1,21 @@ +if confirm('use Europe/Paris as timezone?'): + timezone = 'Europe/Paris' +else: + import pytz + while True: + timezone = raw_input('enter your timezone') + if timezone in pytz.common_timezones: + break + +dbdriver = repo.system_source.dbdriver +if dbdriver == 'postgres': + sql("SET TIME ZONE '%s'" % timezone) + +for entity in schema.entities(): + if entity.final: + continue + change_attribute_type(entity.type, 'creation_date', 'TZDatetime', ask_confirm=False) + change_attribute_type(entity.type, 'modification_date', 'TZDatetime', ask_confirm=False) + +if dbdriver == 'postgres': + sql("SET TIME ZONE UTC") diff -r 38afb7e23c6c -r 63d860a14a17 misc/scripts/ldapuser2ldapfeed.py --- a/misc/scripts/ldapuser2ldapfeed.py Fri Dec 18 09:37:15 2015 +0100 +++ b/misc/scripts/ldapuser2ldapfeed.py Fri Dec 18 09:23:23 2015 +0100 @@ -54,9 +54,9 @@ print('get back', etype, entity.eid) entity.cw_edited = EditedEntity(entity, **entity.cw_attr_cache) if not entity.creation_date: - entity.cw_edited['creation_date'] = datetime.now() + entity.cw_edited['creation_date'] = datetime.utcnow() if not entity.modification_date: - entity.cw_edited['modification_date'] = datetime.now() + entity.cw_edited['modification_date'] = datetime.utcnow() if not entity.upassword: entity.cw_edited['upassword'] = generate_password() extid = entity.cw_metainformation()['extid'] diff -r 38afb7e23c6c -r 63d860a14a17 schemas/base.py --- a/schemas/base.py Fri Dec 18 09:37:15 2015 +0100 +++ b/schemas/base.py Fri Dec 18 09:23:23 2015 +0100 @@ -150,14 +150,16 @@ __permissions__ = PUB_SYSTEM_ATTR_PERMS cardinality = '11' subject = '*' - object = 'Datetime' + object = 'TZDatetime' + class modification_date(RelationType): """latest modification time of an entity""" __permissions__ = PUB_SYSTEM_ATTR_PERMS cardinality = '11' subject = '*' - object = 'Datetime' + object = 'TZDatetime' + class cwuri(RelationType): """internal entity uri""" diff -r 38afb7e23c6c -r 63d860a14a17 server/checkintegrity.py --- a/server/checkintegrity.py Fri Dec 18 09:37:15 2015 +0100 +++ b/server/checkintegrity.py Fri Dec 18 09:23:23 2015 +0100 @@ -372,8 +372,8 @@ {'type': etype}) continue table = SQL_PREFIX + etype - for rel, default in ( ('creation_date', datetime.now()), - ('modification_date', datetime.now()), ): + for rel, default in ( ('creation_date', datetime.utcnow()), + ('modification_date', datetime.utcnow()), ): column = SQL_PREFIX + rel cursor = cnx.system_sql("SELECT %s FROM %s WHERE %s is NULL" % (eidcolumn, table, column)) diff -r 38afb7e23c6c -r 63d860a14a17 server/test/unittest_rql2sql.py --- a/server/test/unittest_rql2sql.py Fri Dec 18 09:37:15 2015 +0100 +++ b/server/test/unittest_rql2sql.py Fri Dec 18 09:23:23 2015 +0100 @@ -1027,10 +1027,10 @@ FROM cw_Societe AS _S, travaille_relation AS rel_travaille0 WHERE rel_travaille0.eid_to=_S.cw_eid AND _S.cw_tel=_S.cw_fax'''), - ("Personne P where X eid 0, X creation_date D, P datenaiss < D, X is Affaire", + ("Personne P where X eid 0, X creation_date D, P tzdatenaiss < D, X is Affaire", '''SELECT _P.cw_eid FROM cw_Affaire AS _X, cw_Personne AS _P -WHERE _X.cw_eid=0 AND _P.cw_datenaiss<_X.cw_creation_date'''), +WHERE _X.cw_eid=0 AND _P.cw_tzdatenaiss<_X.cw_creation_date'''), ("Any N,T WHERE N is Note, N type T;", '''SELECT _N.cw_eid, _N.cw_type diff -r 38afb7e23c6c -r 63d860a14a17 web/views/editcontroller.py --- a/web/views/editcontroller.py Fri Dec 18 09:37:15 2015 +0100 +++ b/web/views/editcontroller.py Fri Dec 18 09:23:23 2015 +0100 @@ -373,7 +373,7 @@ def check_concurrent_edition(self, formparams, eid): req = self._cw try: - form_ts = datetime.fromtimestamp(float(formparams['__form_generation_time'])) + form_ts = datetime.utcfromtimestamp(float(formparams['__form_generation_time'])) except KeyError: # Backward and tests compatibility : if no timestamp consider edition OK return diff -r 38afb7e23c6c -r 63d860a14a17 web/views/forms.py --- a/web/views/forms.py Fri Dec 18 09:37:15 2015 +0100 +++ b/web/views/forms.py Fri Dec 18 09:23:23 2015 +0100 @@ -369,8 +369,8 @@ self.add_hidden('_cwmsgid', msgid) def add_generation_time(self): - # NB repr is critical to avoid truncation of the timestamp - self.add_hidden('__form_generation_time', repr(time.time()), + # use %f to prevent (unlikely) display in exponential format + self.add_hidden('__form_generation_time', '%.6f' % time.time(), eidparam=True) def add_linkto_hidden(self):