diff --git a/nomad/metainfo/__init__.py b/nomad/metainfo/__init__.py
index e9a217aa25570b17a0e72576fa42eb2082a4366e..e27cf60e6009aa7ba83d8375543060f26f47f73b 100644
--- a/nomad/metainfo/__init__.py
+++ b/nomad/metainfo/__init__.py
@@ -1,2 +1,2 @@
 from .metainfo import MSection, MCategory, Definition, Property, Quantity, SubSection, \
-    Section, Category, Package, Enum, m_package, units
+    Section, Category, Package, Enum, Datetime, m_package, units
diff --git a/nomad/metainfo/example.py b/nomad/metainfo/example.py
index 14ac880dd2a37837d1ed89d652615698c50a87b3..9c30137dae6f1f8e3acad16d85671e0d148e41e0 100644
--- a/nomad/metainfo/example.py
+++ b/nomad/metainfo/example.py
@@ -1,8 +1,9 @@
 """ An example metainfo package. """
 
 import numpy as np
+from datetime import datetime
 
-from nomad.metainfo import MSection, MCategory, Section, Quantity, Package, SubSection, Enum, units
+from nomad.metainfo import MSection, MCategory, Section, Quantity, Package, SubSection, Enum, Datetime, units
 
 m_package = Package(links=['http://metainfo.nomad-coe.eu'])
 
@@ -18,6 +19,7 @@ class Parsing(MSection):
     parser_version = Quantity(type=str)
     nomad_version = Quantity(type=str)
     warnings = Quantity(type=str, shape=['0..*'])
+    parse_time = Quantity(type=Datetime)
 
 
 class System(MSection):
@@ -93,6 +95,10 @@ if __name__ == '__main__':
     run = Run()
     run.code_name = 'VASP'
     run.code_version = '1.0.0'
+
+    parsing = run.m_create(Parsing)
+    parsing.parse_time = datetime.now()
+
     run.m_as(VaspRun).x_vasp_raw_format = 'outcar'
     # The same as
     run.x_vasp_raw_format = 'outcar'  # type: ignore
@@ -117,4 +123,4 @@ if __name__ == '__main__':
     run = Run.m_from_dict(serializable)
     print(run.sccs[0].system)
 
-    print(m_package.m_to_dict())  # type: ignore, pylint: disable=undefined-variable
+    # print(m_package.m_to_json(indent=2))  # type: ignore, pylint: disable=undefined-variable
diff --git a/nomad/metainfo/metainfo.py b/nomad/metainfo/metainfo.py
index 227b751605c0db7576f28d8a34274936cd80deab..f85bd37df4a015f23088a360137ccafe1f4eaab5 100644
--- a/nomad/metainfo/metainfo.py
+++ b/nomad/metainfo/metainfo.py
@@ -134,7 +134,7 @@ See the reference of classes :class:`Section` and :class:`Quantities` for detail
 .. autoclass:: Quantity
 """
 
-# TODO validation
+# TODO validation and constraints
 
 from typing import Type, TypeVar, Union, Tuple, Iterable, List, Any, Dict, Set, \
     Callable as TypingCallable, cast
@@ -148,6 +148,9 @@ import itertools
 import numpy as np
 from pint.unit import _Unit
 from pint import UnitRegistry
+import aniso8601
+from datetime import datetime
+import pytz
 
 
 m_package: 'Package' = None
@@ -384,13 +387,40 @@ class Reference(DataType):
         return MProxy(value)
 
 
+class __Datetime(DataType):
+
+    def __parse(self, datetime_str: str) -> datetime:
+        try:
+            try:
+                return aniso8601.parse_datetime(datetime_str)
+            except ValueError:
+                date = aniso8601.parse_date(datetime_str)
+                return datetime(date.year, date.month, date.day)
+        except Exception:
+            raise TypeError('Invalid date literal "{0}"'.format(datetime_str))
+
+    def set_normalize(self, section: 'MSection', quantity_def: 'Quantity', value: Any) -> Any:
+        if isinstance(value, str):
+            value = self.__parse(value)
+
+        if not isinstance(value, datetime):
+            raise TypeError('%s is not a datetime.' % value)
+
+        return value
+
+    def serialize(self, section: 'MSection', quantity_def: 'Quantity', value: Any) -> Any:
+        value.replace(tzinfo=pytz.utc)
+        return value.isoformat()
+
+    def deserialize(self, section: 'MSection', quantity_def: 'Quantity', value: Any) -> Any:
+        return self.__parse(value)
+
+
 Dimension = __Dimension()
 Unit = __Unit()
 QuantityType = __QuantityType()
 Callable = __Callable()
-
-
-# TODO class Datetime(DataType)
+Datetime = __Datetime()
 
 
 class MObjectMeta(type):
@@ -737,10 +767,6 @@ class MSection(metaclass=MObjectMeta):
                     'The value %s is not an enum value for quantity %s.' %
                     (value, quantity_def))
 
-        elif quantity_def in [Quantity.type, Quantity.derived]:
-            # TODO check these special cases for Quantity quantities
-            pass
-
         elif quantity_def.type == Any:
             pass
 
@@ -999,45 +1025,43 @@ class MSection(metaclass=MObjectMeta):
         dct.pop('m_parent_index', None)
         dct.pop('m_parent_sub_section', None)
 
-        def items():
-            for name, sub_section_def in section_def.all_sub_sections.items():
-                if name in dct:
-                    sub_section_value = dct.pop(name)
-                    if sub_section_def.repeats:
-                        yield name, [
-                            sub_section_def.sub_section.section_cls.m_from_dict(sub_section_dct)
-                            for sub_section_dct in sub_section_value]
+        section = cls()
+
+        for name, sub_section_def in section_def.all_sub_sections.items():
+            if name in dct:
+                sub_section_value = dct.pop(name)
+                if sub_section_def.repeats:
+                    for sub_section_dct in sub_section_value:
+                        sub_section = sub_section_def.sub_section.section_cls.m_from_dict(sub_section_dct)
+                        section.m_add_sub_section(sub_section_def, sub_section)
+
+                else:
+                    sub_section = sub_section_def.sub_section.section_cls.m_from_dict(sub_section_value)
+                    section.m_add_sub_section(sub_section_def, sub_section)
+
+        for name, quantity_def in section_def.all_quantities.items():
+            if name in dct:
+                quantity_value = dct[name]
+
+                if type(quantity_def.type) == np.dtype:
+                    quantity_value = np.asarray(quantity_value)
+
+                if isinstance(quantity_def.type, DataType):
+                    dimensions = len(quantity_def.shape)
+                    if dimensions == 0:
+                        quantity_value = quantity_def.type.deserialize(
+                            section, quantity_def, quantity_value)
+                    elif dimensions == 1:
+                        quantity_value = list(
+                            quantity_def.type.deserialize(section, quantity_def, item)
+                            for item in quantity_value)
                     else:
-                        yield name, sub_section_def.sub_section.section_cls.m_from_dict(sub_section_value)
-
-            for name, quantity_def in section_def.all_quantities.items():
-                if name in dct:
-                    quantity_value = dct[name]
-
-                    if type(quantity_def.type) == np.dtype:
-                        quantity_value = np.asarray(quantity_value)
-
-                    if isinstance(quantity_def.type, DataType):
-                        dimensions = len(quantity_def.shape)
-                        # TODO hand in the context, which is currently create after!
-                        if dimensions == 0:
-                            quantity_value = quantity_def.type.deserialize(
-                                None, quantity_def, quantity_value)
-                        elif dimensions == 1:
-                            quantity_value = list(
-                                quantity_def.type.deserialize(None, quantity_def, item)
-                                for item in quantity_value)
-                        else:
-                            raise MetainfoError(
-                                'Only numpy quantities can have more than 1 dimension.')
+                        raise MetainfoError(
+                            'Only numpy quantities can have more than 1 dimension.')
 
-                    yield name, quantity_value
+                section.m_data.dct[name] = quantity_value  # type: ignore
 
-        dct = {key: value for key, value in items()}
-        section_instance = cast(MSectionBound, section_def.section_cls())
-        # TODO !do not update, but set directly!
-        section_instance.m_update(**dct)
-        return section_instance
+        return section
 
     def m_to_json(self, **kwargs):
         """Returns the data of this section as a json string. """
@@ -1271,9 +1295,6 @@ class Quantity(Property):
     virtual: 'Quantity' = None
 
     # TODO derived_from = Quantity(type=Quantity, shape=['0..*'])
-    # TODO categories = Quantity(type=Category, shape=['0..*'])
-    # TODO converter = Quantity(type=Converter), a class with set of functions for
-    #      normalizing, (de-)serializing values.
 
     def __get__(self, obj, cls):
         if obj is None: