| | 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 | |