Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py	(revision 10551)
+++ django/db/models/fields/__init__.py	(working copy)
@@ -636,6 +636,61 @@
         defaults.update(kwargs)
         return super(DecimalField, self).formfield(**defaults)
 
+class DurationProxy(object):
+    def __init__(self, field):
+        self.field_name = field.name
+
+    def __get__(self, instance=None, owner=None):
+        if instance is None:
+            raise AttributeError, "%s can only be accessed from %s instances." % (self.field_name, owner.__name__)
+        if self.field_name not in instance.__dict__:
+            return None
+        return instance.__dict__[self.field_name]
+
+    def __set__(self, instance, value):
+        if value and not isinstance(value, datetime.timedelta):
+            value = datetime.timedelta(seconds=float(value))
+        instance.__dict__[self.field_name] = value
+
+class DurationField(Field):
+    def __init__(self, *args, **kwargs):
+        super(DurationField, self).__init__(*args, **kwargs)
+        self.max_digits, self.decimal_places = 20, 6
+
+    def get_internal_type(self):
+        return "DecimalField"
+
+    def contribute_to_class(self, cls, name):
+        super(DurationField, self).contribute_to_class(cls, name)
+        setattr(cls, name, DurationProxy(self))
+
+    def get_db_prep_save(self, value):
+        if value is None:
+            return None
+        return str(value.days * 24 * 3600 + value.seconds + float(value.microseconds) / 1000000)
+
+    def to_python(self, value):
+        if isinstance(value, datetime.timedelta):
+            return value
+        try:
+            return datetime.timedelta(seconds=float(value))
+        except (TypeError, ValueError):
+            raise validators.ValidationError('This value must be a real number.')
+        except OverflowError:
+            raise validators.ValidationError('The maximum allowed value is %s' % datetime.timedelta.max)
+
+    def flatten_data(self, follow, obj=None):
+        val = self._get_val_from_obj(obj)
+        if val is None or val is '':
+            return ''
+        return {self.name: self.get_db_prep_save(val)}
+
+    def formfield(self, form_class=forms.DurationField, **kwargs):
+        return super(DurationField, self).formfield(form_class, **kwargs)
+
+    def get_manipulator_field_objs(self):
+        return [curry(oldforms.DecimalField, max_digits=self.max_digits, decimal_places=self.decimal_places)]
+
 class EmailField(CharField):
     def __init__(self, *args, **kwargs):
         kwargs['max_length'] = kwargs.get('max_length', 75)
Index: django/forms/fields.py
===================================================================
--- django/forms/fields.py	(revision 10551)
+++ django/forms/fields.py	(working copy)
@@ -28,7 +28,7 @@
 from django.utils.encoding import smart_unicode, smart_str
 
 from util import ErrorList, ValidationError
-from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget
+from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, DurationWidget, SplitDateTimeWidget, SplitHiddenDateTimeWidget
 from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile
 
 __all__ = (
@@ -40,7 +40,7 @@
     'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField',
     'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
     'SplitDateTimeField', 'IPAddressField', 'FilePathField', 'SlugField',
-    'TypedChoiceField'
+    'TypedChoiceField', 'DurationField',
 )
 
 # These values, if given to to_python(), will trigger the self.required check.
@@ -884,6 +884,33 @@
             return datetime.datetime.combine(*data_list)
         return None
 
+class DurationField(MultiValueField):
+    widget = DurationWidget
+
+    def __init__(self, *args, **kwargs):
+        errors = self.default_error_messages.copy()
+        fields = (
+            IntegerField(max_value=999999999, min_value=-999999999),
+            IntegerField(label='Hours', max_value=23, min_value=0),
+            IntegerField(label='Minutes', max_value=59, min_value=0),
+            IntegerField(label='Seconds', max_value=59, min_value=0),
+            IntegerField(label='Microseconds', max_value=999999, min_value=0),
+        )
+        super(DurationField, self).__init__(fields, *args, **kwargs)
+
+    def compress(self, data_list):
+        if data_list == [None] * 5:
+            raise ValidationError(gettext(u'This field is required.'))
+        if data_list:
+            return datetime.timedelta(
+                days=data_list[0] or 0,
+                hours=data_list[1] or 0,
+                minutes=data_list[2] or 0,
+                seconds=data_list[3] or 0,
+                microseconds=data_list[4] or 0,
+            )
+        return None
+
 ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
 
 class IPAddressField(RegexField):
Index: django/forms/widgets.py
===================================================================
--- django/forms/widgets.py	(revision 10551)
+++ django/forms/widgets.py	(working copy)
@@ -26,7 +26,7 @@
     'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput',
     'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
     'CheckboxSelectMultiple', 'MultiWidget',
-    'SplitDateTimeWidget',
+    'SplitDateTimeWidget', 'DurationWidget',
 )
 
 MEDIA_TYPES = ('css','js')
@@ -706,3 +706,25 @@
     def __init__(self, attrs=None):
         widgets = (HiddenInput(attrs=attrs), HiddenInput(attrs=attrs))
         super(SplitDateTimeWidget, self).__init__(widgets, attrs)
+
+class DurationWidget(MultiWidget):
+    def __init__(self, attrs=None):
+        attrs = attrs or {}
+        widgets = (
+            TextInput(attrs=dict(attrs, size=4, maxlength=10, title='Days')),
+            TextInput(attrs=dict(attrs, size=1, maxlength=2, title='Hours')),
+            TextInput(attrs=dict(attrs, size=1, maxlength=2, title='Minutes')),
+            TextInput(attrs=dict(attrs, size=1, maxlength=2, title='Seconds')),
+            TextInput(attrs=dict(attrs, size=5, maxlength=6, title='Microseconds')),
+        )
+        super(DurationWidget, self).__init__(widgets, attrs)
+
+    def decompress(self, value):
+        if value:
+            hours, seconds = divmod(value.seconds, 3600)
+            minutes, seconds = divmod(seconds, 60)
+            return [value.days, hours, minutes, seconds, value.microseconds]
+        return [None, None, None, None, None]
+
+    def format_output(self, rendered_widgets):
+        return u'%s days, %s : %s : %s . %s' % tuple(rendered_widgets)
