Index: django/db/models/fields/duration.py
===================================================================
--- django/db/models/fields/duration.py	(revision 0)
+++ django/db/models/fields/duration.py	(revision 0)
@@ -0,0 +1,55 @@
+from django.forms.fields import DurationField as FDurationField
+from django.forms.fields import TimeDelta
+from django.db.models.fields import Field
+from django.core.exceptions import ValidationError
+from django.db import connection
+
+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, TimeDelta):
+            value = TimeDelta(microseconds=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
+        if not isinstance(value, TimeDelta):
+            value = TimeDelta(value)
+        t = value.days * 24 * 3600 * 1000000 + value.seconds * 1000000 + value.microseconds
+        return connection.ops.value_to_db_decimal(t, 20, 0) # max value 86399999999999999999 microseconds
+
+    def to_python(self, value):
+        if isinstance(value, TimeDelta):
+            return value
+        try:
+            return TimeDelta(microseconds=float(value))
+        except (TypeError, ValueError):
+            raise ValidationError('The value must be an integer.')
+        except OverflowError:
+            raise ValidationError('The maximum allowed value is %s' % TimeDelta.max)
+
+    def formfield(self, form_class=FDurationField, **kwargs):
+        return super(DurationField, self).formfield(form_class, **kwargs)
+
Index: django/forms/fields.py
===================================================================
--- django/forms/fields.py	(revision 10838)
+++ django/forms/fields.py	(working copy)
@@ -25,6 +25,7 @@
 
 import django.core.exceptions
 from django.utils.translation import ugettext_lazy as _
+from django.utils.datastructures import SortedDict
 from django.utils.encoding import smart_unicode, smart_str
 
 from util import ErrorList, ValidationError
@@ -885,6 +886,93 @@
             return datetime.datetime.combine(*data_list)
         return None
 
+class TimeDelta(datetime.timedelta):
+    values_in_microseconds = SortedDict((
+        ('y', 31556925993600), # 52.177457 * (7*24*60*60*1000*1000)
+        ('m', 2629743832800), # 4.34812141 * (7*24*60*60*1000*1000)
+        ('w', 604800000000), # 7*24*60*60*1000*1000
+        ('d', 86400000000), # 24*60*60*1000*1000
+        ('h', 3600000000), # 60*60*1000*1000
+        ('min', 60000000), # 60*1000*1000
+        ('s',  1000000), # 1000*1000
+        ('ms', 1000),
+        ('us', 1),
+    ))
+
+    def __new__(self, *args, **kw):
+        assert not args, "Can't accept args"
+        usec = kw.get('microseconds')
+        if usec and not isinstance(usec, datetime.timedelta):
+            kw['microseconds'] = float(usec)
+        return datetime.timedelta.__new__(TimeDelta, *args, **kw)
+
+    def __unicode__(self):
+        if not self:
+            return u"0"
+        vals = []
+        mis = self.days * 24 * 3600 * 1000000 + self.seconds * 1000000 + self.microseconds
+        for k in self.values_in_microseconds:
+            if mis >= self.values_in_microseconds[k]:
+                diff, mis = divmod(mis, self.values_in_microseconds[k])
+                vals.append("%d%s" % (diff, k))
+        return u" ".join(vals)
+    
+class DurationField(Field):
+    default_error_messages = {
+        'invalid': _(u'Enter a valid duration.'),
+        'min_value': _(u'Ensure this self is greater than or equal to %(min)s.'),
+        'max_value': _(u'Ensure this self is less than or equal to %(max)s.'),
+    }
+
+    def __init__(self, min_value=None, max_value=None, *args, **kwargs):
+        super(DurationField, self).__init__(*args, **kwargs)
+        self.min_value, self.max_value = min_value, max_value
+
+    def to_timedelta(self, value):
+        """
+        Takes an Unicode self and converts it to a datetime.timedelta object.
+        1y 7m 6w 3d 18h 30min 23s 10ms 150mis => 
+         1 year 7 months 6 weeks 3 days 18 hours 30 minutes 23 seconds 10 milliseconds 150 microseconds
+         => datetime.timedelta(624, 6155, 805126)
+        """
+        if not value or value == '0':
+            return TimeDelta(microseconds=0)
+
+        pairs = []
+        for b in value.lower().split():
+            for index, char in enumerate(b):
+                if not char.isdigit():
+                    pairs.append((b[:index], b[index:])) #digits, letters
+                    break
+        if not pairs:
+            raise ValidationError(self.error_messages['invalid'])
+
+        microseconds = 0
+        for digits, chars in pairs:
+            if not digits or not chars:
+                raise ValidationError(self.error_messages['invalid'])
+            microseconds += int(digits) * TimeDelta.values_in_microseconds[chars]
+
+        return TimeDelta(microseconds=microseconds)
+
+    def from_timedelta(self, value):
+        if not value:
+            return u"0"
+        return unicode(value)
+
+    def clean(self, value):
+        "Validates max_value and min_value. Returns a datetime.timedelta object."
+        value = self.to_timedelta(value)
+
+        if self.max_value is not None and value > self.max_value:
+            raise ValidationError(self.error_messages['max_value'] % {'max': self.max_value})
+
+        if self.min_value is not None and value < self.min_value:
+            raise ValidationError(self.error_messages['min_value'] % {'min': self.min_value})
+
+        return value
+
+
 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):
