[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
--- 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
--- 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 = []
--- 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:
--- 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):
--- 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)
--- 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)
--- /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")
--- 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']
--- 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"""
--- 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))
--- 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
--- 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
--- 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):