diff --git a/CHANGES.rst b/CHANGES.rst
index c7a1da8..5d06033 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,7 +5,8 @@ Changelog
1.5.3 (unreleased)
------------------
-- Nothing changed yet.
+- Implement new deserializer for datetime fields.
+ [mbaechtold]
1.5.2 (2015-07-13)
diff --git a/README.rst b/README.rst
index 8250739..dc1fc68 100644
--- a/README.rst
+++ b/README.rst
@@ -34,6 +34,10 @@ Actually tested and supported fields
needs a datetime.date or datetime.datetime object, or a string in the
following format "%Y-%m-%d"
+- Datetime
+ needs a datetime.datetime object, or a string in the
+ format "'%Y-%m-%d %H:%M:%S"
+
Default pipelines
=================
diff --git a/transmogrify/dexterity/converters.py b/transmogrify/dexterity/converters.py
index 569ea00..5b0e315 100644
--- a/transmogrify/dexterity/converters.py
+++ b/transmogrify/dexterity/converters.py
@@ -1,5 +1,6 @@
from .interfaces import IDeserializer
from .interfaces import ISerializer
+from DateTime import DateTime
from datetime import datetime
from plone.app.textfield.interfaces import IRichText
from plone.app.textfield.value import RichTextValue
@@ -11,6 +12,7 @@
from zope.interface import implementer
from zope.schema.interfaces import ICollection
from zope.schema.interfaces import IDate
+from zope.schema.interfaces import IDatetime
from zope.schema.interfaces import IField
from zope.schema.interfaces import IFromUnicode
from zope.schema.interfaces import IObject
@@ -382,6 +384,33 @@ def __call__(self, value, filestore, item,
return value
+@implementer(IDeserializer)
+@adapter(IDatetime)
+class DatetimeDeserializer(object):
+
+ def __init__(self, field):
+ self.field = field
+
+ def __call__(self, value, filestore, item,
+ disable_constraints=False, logger=None):
+ if isinstance(value, basestring):
+ value = DateTime(value).asdatetime()
+ try:
+ self.field.validate(value)
+ except Exception as e:
+ if not disable_constraints:
+ raise e
+ else:
+ if logger:
+ logger(
+ "%s is invalid in %s: %s" % (
+ self.field.__name__,
+ item['_path'],
+ e)
+ )
+ return value
+
+
@implementer(ISerializer)
@adapter(IField)
class DefaultSerializer(object):
diff --git a/transmogrify/dexterity/converters.zcml b/transmogrify/dexterity/converters.zcml
index 09bfcc2..97d1406 100644
--- a/transmogrify/dexterity/converters.zcml
+++ b/transmogrify/dexterity/converters.zcml
@@ -16,6 +16,7 @@
+
diff --git a/transmogrify/dexterity/testing.py b/transmogrify/dexterity/testing.py
index d3257c1..6b8cf05 100644
--- a/transmogrify/dexterity/testing.py
+++ b/transmogrify/dexterity/testing.py
@@ -2,6 +2,7 @@
from collective.transmogrifier.interfaces import ISectionBlueprint
from collective.transmogrifier.sections.tests import SampleSource
from datetime import date
+from datetime import datetime
from ftw.builder.testing import BUILDER_LAYER
from ftw.builder.testing import functional_session_factory
from ftw.builder.testing import set_builder_session_factory
@@ -72,6 +73,10 @@ class ITestSchema(form.Schema):
title=u'test_date',
)
+ test_datetime = schema.Datetime(
+ title=u'test_datetime',
+ )
+
fancy_text = RichText(
title=u"Fancy text",
)
@@ -131,6 +136,7 @@ def __init__(self, transmogrifier, name, options, previous):
'data': zptlogo,
'filename': 'zptlogo.gif'},
test_date='2010-10-12',
+ test_datetime='2010-10-12 17:59:59',
fieldnotchanged='nochange',
),
dict(_path='/two',
@@ -142,6 +148,7 @@ def __init__(self, transmogrifier, name, options, previous):
test_file=zptlogo,
_filename="testlogo.gif",
test_date=date(2010, 0o1, 0o1, ),
+ test_datetime=datetime(2010, 0o1, 0o1, 17, 59, 59),
fieldnotchanged='nochange',
),
)
diff --git a/transmogrify/dexterity/tests/schemaupdater.txt b/transmogrify/dexterity/tests/schemaupdater.txt
index 6db3d20..8ff47cf 100644
--- a/transmogrify/dexterity/tests/schemaupdater.txt
+++ b/transmogrify/dexterity/tests/schemaupdater.txt
@@ -70,6 +70,14 @@ DateFields:
>>> two.test_date
datetime.date(2010, 1, 1)
+DatetimeFields:
+
+ >>> spam.test_datetime
+ datetime.datetime(2010, 10, 12, 17, 59, 59)
+
+ >>> two.test_datetime
+ datetime.datetime(2010, 1, 1, 17, 59, 59)
+
Won't touch already existing values
>>> transmogrifier = Transmogrifier(portal)
diff --git a/transmogrify/dexterity/tests/testconverters.py b/transmogrify/dexterity/tests/testconverters.py
index 819ae0b..48aa5ed 100644
--- a/transmogrify/dexterity/tests/testconverters.py
+++ b/transmogrify/dexterity/tests/testconverters.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+from datetime import datetime
from ftw.builder import Builder
from ftw.builder import create
from plone.app.textfield import RichText
@@ -9,6 +10,7 @@
from z3c.relationfield.relation import RelationValue
from z3c.relationfield.schema import RelationChoice
from z3c.relationfield.schema import RelationList
+from zope.schema import Datetime
import pprint
import unittest
import zope.testing
@@ -195,3 +197,21 @@ def test_filestore(self):
"x-application/cow",
"Content type from dict should override default")
self.assertEqual(rtv.encoding, "latin-1")
+
+
+class TestDatetimeDeserializer(unittest.TestCase):
+
+ layer = TRANSMOGRIFY_DEXTERITY_FUNCTIONAL_TESTING
+
+ def setUp(test):
+ test.pp = pprint.PrettyPrinter(indent=4)
+ # TODO: This should read the zcml instead
+ zope.component.provideAdapter(converters.DatetimeDeserializer)
+
+ def test_datetime_deserializer(self):
+ deserializer = IDeserializer(Datetime())
+ value = deserializer('2015-12-31 17:59:59', None, None)
+ self.assertEqual(
+ datetime(2015, 12, 31, 17, 59, 59),
+ value
+ )