TimedeltaField for django models
PostgreSQL can store data as INTERVAL type, which is close to meaning the same as python’s timedelta object (although better in a couple of ways).
I have lots of use for timedelta objects, and having code that basically wrapped integer objects as a number of seconds was common. This module combines the two:
- a timedelta.TimedeltaField() object that transparently converts to and from datetime.timedelta
- storage of the data as an INTERVAL in PostgreSQL, or a string in other databases. (Other databases will be considered if I ever use them, or receive patches).
The coolest part of this package is the way it manipulates strings entered by users, and presents them. Any string of the format:
[X weeks,] [Y days,] [Z hours,] [A minutes,] [B seconds]
will be converted to a timedelta object. Even shortened versions can be used: hrs, hr or h will also suffice. The parsing ignores trailing ‘s’, but is smart about adding them in when presenting the data to the user.
To use, install the package, and use the field:
from django.db import models import timedelta class MyModel(models.Model): the_timedelta = timedelta.fields.TimedeltaField()
There are also some useful methods in helpers.py to work with timedelta objects. (eg, multiply, divide, modulo and percentages).
Additionally, there are two template filters,
will convert a timedelta object into a valid string.
from django.db import models import timedelta class Event(models.Model): start = models.DateTimeField() duration = timedelta.fields.TimedeltaField() @property def finish(self): return self.start + self.duration
Storing data within the field:
evt = Event.objects.create( start=datetime.datetime.now(), duration=datetime.timedelta(hours=1) ) print evt.finish evt.duration = datetime.timedelta(minutes=3) print evt.finish # We can use valid strings of the format described above. Event.objects.update(duration='2 hours, 45 minutes') evt = Event.objects.get(pk=evt.pk) print evt.finish # We can also assign directly to this field a valid string. evt.duration = '3 days, 2 hours' evt.save() # Note: we need to re-fetch to ensure conversion to timedelta evt = Event.objects.get(pk=evt.pk) print evt.finish
You can just use a ModelForm, and it will automatically select the TimedeltaFormField, which will handle the conversion between formatted strings and timedelta objects.
Or you may use the form field directly:
from django import forms import timedelta class EventForm(forms.Form): start = forms.DateTimeField() duration = timedelta.forms.TimedeltaFormField()
This form field will display a value in the format:
2 day, 3 hours, 1 minute
And will parse data from a similar format.
Have a look in tests.py for examples of the form field/widget output.
Returns a string of the format:
“2 weeks, 7 hours, 1 day”
display may be one of the strings ‘minimal’, ‘short’ or ‘long’.
Returns a string of the format:
As per ISO8601. For timedeltas less than a whole day, the ‘alt’ format is supported:
Parse a string from the nice_repr formats.
Allow dividing one timedelta by another, or by an integer, float or decimal value.
Allows modulo division of one timedelta by another, or by an integer.
Returns what percentage of the first timedelta the second is, as a float.
Returns what percentage of the first timedelta the second is, as a decimal.
Allows for the multiplication of timedeltas by numbers.
Round the first argument (which must be a datetime, time, or timedelta object), to the nearest interval of the second argument.
Return a decimal value of the number of hours that this timedelta object refers to.
A wrapper for python < 2.7’s lack of timedelta.total_seconds()
Parse ISO8601 strings. Thanks to Guillame Libersat, we can generate them.
Handle strings with times in other languages. I’m not really sure about how to do this, but it may be useful.
0.7.10: Fix issue for Python3/dumpdata, and None values.
0.7.9: Update PyPI classifiers/supported python versions.
0.7.8: Fix for django migrations.
0.7.7: Minor bugfix for template tag.
0.7.4: Improve template tags so the content they render can be parsed.
0.7.0: Support for django 1.5
0.6.7: Added LICENSE file.
0.6.3: Correctly parse ‘1h’ as one hour (previously required 1hr).
0.6.2: Remember to include VERSION number.
0.6.0: Added total_seconds helper (for python < 2.7)
0.5.3: Include long_description from this file.
0.5.2: Added decimal_percentage, which gives us a decimal.Decimal object.
0.5.1: Bugfixes from Mike Fogel.
0.4.7: Bugfix from savemu: use unicode() instead of str()
0.4.5: Restore functionality for django <1.2 (thanks Yoav Aner).
0.4.3: Added helpers.modulo, to allow remainder division of timedlelta objects.