| 889 | class TimeDelta(datetime.timedelta): |
| 890 | values_in_microseconds = SortedDict(( |
| 891 | ('y', 31556925993600), # 52.177457 * (7*24*60*60*1000*1000) |
| 892 | ('m', 2629743832800), # 4.34812141 * (7*24*60*60*1000*1000) |
| 893 | ('w', 604800000000), # 7*24*60*60*1000*1000 |
| 894 | ('d', 86400000000), # 24*60*60*1000*1000 |
| 895 | ('h', 3600000000), # 60*60*1000*1000 |
| 896 | ('min', 60000000), # 60*1000*1000 |
| 897 | ('s', 1000000), # 1000*1000 |
| 898 | ('ms', 1000), |
| 899 | ('us', 1), |
| 900 | )) |
| 901 | |
| 902 | def __new__(self, *args, **kw): |
| 903 | assert not args, "Can't accept args" |
| 904 | usec = kw.get('microseconds') |
| 905 | if usec and not isinstance(usec, datetime.timedelta): |
| 906 | kw['microseconds'] = float(usec) |
| 907 | return datetime.timedelta.__new__(TimeDelta, *args, **kw) |
| 908 | |
| 909 | def __unicode__(self): |
| 910 | if not self: |
| 911 | return u"0" |
| 912 | vals = [] |
| 913 | mis = self.days * 24 * 3600 * 1000000 + self.seconds * 1000000 + self.microseconds |
| 914 | for k in self.values_in_microseconds: |
| 915 | if mis >= self.values_in_microseconds[k]: |
| 916 | diff, mis = divmod(mis, self.values_in_microseconds[k]) |
| 917 | vals.append("%d%s" % (diff, k)) |
| 918 | return u" ".join(vals) |
| 919 | |
| 920 | class DurationField(Field): |
| 921 | default_error_messages = { |
| 922 | 'invalid': _(u'Enter a valid duration.'), |
| 923 | 'min_value': _(u'Ensure this self is greater than or equal to %(min)s.'), |
| 924 | 'max_value': _(u'Ensure this self is less than or equal to %(max)s.'), |
| 925 | } |
| 926 | |
| 927 | def __init__(self, min_value=None, max_value=None, *args, **kwargs): |
| 928 | super(DurationField, self).__init__(*args, **kwargs) |
| 929 | self.min_value, self.max_value = min_value, max_value |
| 930 | |
| 931 | def to_timedelta(self, value): |
| 932 | """ |
| 933 | Takes an Unicode self and converts it to a datetime.timedelta object. |
| 934 | 1y 7m 6w 3d 18h 30min 23s 10ms 150mis => |
| 935 | 1 year 7 months 6 weeks 3 days 18 hours 30 minutes 23 seconds 10 milliseconds 150 microseconds |
| 936 | => datetime.timedelta(624, 6155, 805126) |
| 937 | """ |
| 938 | if not value or value == '0': |
| 939 | return TimeDelta(microseconds=0) |
| 940 | |
| 941 | pairs = [] |
| 942 | for b in value.lower().split(): |
| 943 | for index, char in enumerate(b): |
| 944 | if not char.isdigit(): |
| 945 | pairs.append((b[:index], b[index:])) #digits, letters |
| 946 | break |
| 947 | if not pairs: |
| 948 | raise ValidationError(self.error_messages['invalid']) |
| 949 | |
| 950 | microseconds = 0 |
| 951 | for digits, chars in pairs: |
| 952 | if not digits or not chars: |
| 953 | raise ValidationError(self.error_messages['invalid']) |
| 954 | microseconds += int(digits) * TimeDelta.values_in_microseconds[chars] |
| 955 | |
| 956 | return TimeDelta(microseconds=microseconds) |
| 957 | |
| 958 | def from_timedelta(self, value): |
| 959 | if not value: |
| 960 | return u"0" |
| 961 | return unicode(value) |
| 962 | |
| 963 | def clean(self, value): |
| 964 | "Validates max_value and min_value. Returns a datetime.timedelta object." |
| 965 | value = self.to_timedelta(value) |
| 966 | |
| 967 | if self.max_value is not None and value > self.max_value: |
| 968 | raise ValidationError(self.error_messages['max_value'] % {'max': self.max_value}) |
| 969 | |
| 970 | if self.min_value is not None and value < self.min_value: |
| 971 | raise ValidationError(self.error_messages['min_value'] % {'min': self.min_value}) |
| 972 | |
| 973 | return value |
| 974 | |
| 975 | |