Skip to content

Instantly share code, notes, and snippets.

@tarnacious
Last active August 29, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tarnacious/1a5c81295a5ea82c3aac to your computer and use it in GitHub Desktop.
Save tarnacious/1a5c81295a5ea82c3aac to your computer and use it in GitHub Desktop.
Schematics Custom Datetime Type
from dateutil.parser import parse
from schematics.exceptions import ConversionError
from schematics.types import BaseType
import datetime
class CustomDateTimeType(BaseType):
""" Uses dateutil to parse date string and a serialized format to
strftime it back
:param serialized_format:
The output format suitable for Python ``strftime``.
Default: ``'%Y-%m-%dT%H:%M:%S.%f'``
"""
SERIALIZED_FORMAT = '%Y-%m-%dT%H:%M:%S.%f'
MESSAGES = {
'parse-message': u'Could not parse {0}, {1}',
'parse': u'Could not parse {0}, should be a valid date.'
}
def __init__(self, serialized_format=None, **kwargs):
"""
"""
if serialized_format is not None:
self.serialized_format = serialized_format
else:
self.serialized_format = self.SERIALIZED_FORMAT
super(CustomDateTimeType, self).__init__(**kwargs)
def to_native(self, value, context=None):
if isinstance(value, datetime.datetime):
return value
try:
return parse(value, dayfirst=True)
except ValueError, e:
raise ConversionError(
self.messages['parse-message'].format(value, e.message))
except Exception, e:
raise ConversionError(self.messages['parse'].format(value))
def to_primitive(self, value, context=None):
if callable(self.serialized_format):
return self.serialized_format(value)
return value.strftime(self.serialized_format)
Python 2.7.9 (default, Feb 10 2015, 15:53:51)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from schematics.models import Model
>>> from schematics.types import StringType
>>> from custom_datetype import CustomDateTimeType
>>> class Person(Model):
... name = StringType(required=True)
... useby = CustomDateTimeType()
...
>>>
>>>
>>> person = Person({'name': u'Joe Strummer',
... 'useby': 'Sat Oct 11 17:13:46 UTC 2003'})
>>>
>>> print person.name
Joe Strummer
>>> print person.useby
2003-10-11 17:13:46+00:00
>>> print type(person.useby)
<type 'datetime.datetime'>
>>> print person.to_primitive()
{'name': u'Joe Strummer', 'useby': '2003-10-11T17:13:46.000000'}
>>> person.to_native()
{'name': u'Joe Strummer', 'useby': datetime.datetime(2003, 10, 11, 17, 13, 46, tzinfo=tzutc())}
>>> Person({'name': u'Joe Strummer', 'useby': '30-6-2015'}).useby
datetime.datetime(2015, 6, 30, 0, 0)
>>> Person({'name': u'Joe Strummer', 'useby': '6-30-2015'}).useby
datetime.datetime(2015, 6, 30, 0, 0)
>>> Person({'name': u'Joe Strummer', 'useby': '30-30-2015'})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/tarn/projects/datetype/lib/python2.7/site-packages/schematics/models.py", line 247, in __init__
self._data = self.convert(raw_data, strict=strict, mapping=deserialize_mapping)
File "/Users/tarn/projects/datetype/lib/python2.7/site-packages/schematics/models.py", line 294, in convert
return convert(self.__class__, raw_data, **kw)
File "/Users/tarn/projects/datetype/lib/python2.7/site-packages/schematics/transforms.py", line 419, in convert
partial=partial, strict=strict, mapping=mapping)
File "/Users/tarn/projects/datetype/lib/python2.7/site-packages/schematics/transforms.py", line 119, in import_loop
raise ModelConversionError(errors)
schematics.exceptions.ModelConversionError: {'useby': [u'Could not parse 30-30-2015, month must be in 1..12']}
>>>
schematics
python-dateutil
@tobigue
Copy link

tobigue commented Jun 19, 2015

Looks nice! :)

For our purposes I'd put dayfirst=True in the call of dateutil.parser.parse (maybe make it configurable), as formats like dd.mm.yyyy are the standard here and mm/dd/yyyy are not used.

Also, dateutil gives nice error messages (e.g. "month has to be in 1 .. 12"), maybe it's worth forwarding those.

@tarnacious
Copy link
Author

I've updated the gist to include both those suggestions and some examples of the new functionality, and an example of to_native() which returns datetime objects :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment