Gaurav Tomer
Gaurav Tomer

Reputation: 741

TypeError: unsupported operand type(s) for -: 'datetime.time' and 'datetime.time'

my models.py:

class Attendancename(models.Model):
    teacher_name = models.ForeignKey(Teachername, default='Ram')
    date = models.DateField('Date', default=datetime.datetime.today)
    intime = models.TimeField('IN-TIME', auto_now=True)
    outtime = models.TimeField('OUT-TIME', auto_now=True)

    def hours_conversion(self):
        startdelta = datetime.timedelta(hours=self.intime.hours, minutes=self.intime.minutes, seconds=self.intime.seconds)
        enddelta = datetime.timedelta(hours=self.outtime.hours, minutes=self.outtime.minutes, seconds=self.outtime.seconds)
        return (enddelta-startdelta).seconds/3600

    def __str__(self):
        return "%s" %self.teacher_name

my views.py:

def add_atten(request):
    if request.method == 'POST':
        form = AttendancenameForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('student:listatten'))
        else:
            print(form.errors)
    else:       
        form = AttendancenameForm()
    return render(request, 'add_atten.html', {'form': form},)

my forms.py:

class AttendancenameForm(ModelForm):
    intime = forms.TimeField(input_formats=('%H:%M',))
    outtime = forms.TimeField(input_formats=('%H:%M',))
    teacher_name = forms.ModelChoiceField(queryset=Teachername.objects.all())
    class Meta:
        model = Attendancename
        fields = ('teacher_name', 'date', 'intime', 'outtime',)

Actually I'm trying to calculate total number of hours based on difference of 'intime' and 'outtime' in my models.py file but it raises above erroe. I think I'm doing syntax error. Can anybody Please tell me what is the correct syntax or method to do so? Any body please suggest me what to do to fix it?

Upvotes: 19

Views: 67039

Answers (2)

cottontail
cottontail

Reputation: 23141

As OldTinfoil mentioned, the most straightforward solution is to convert the datetime.time objects into datetime.datetime objects and find the difference. The difference is a datetime.timedelta object from which you can extract the difference in seconds using .total_seconds(). From there, you can convert the difference into different resolutions such as hours, minutes etc.

from datetime import datetime, time

# sample hours
t1 = time(23, 0, 57)
t2 = time(12, 20, 40)

# convert into datetimes
dt1 = datetime.combine(datetime.now(), t1)
dt2 = datetime.combine(datetime.now(), t2)

# compute difference
delta = dt1 - dt2                               # <--- datetime.timedelta(seconds=38417)
diff_in_seconds = delta.total_seconds()         # 38417.0
diff_in_hours = delta.total_seconds() // 3600   # 10.0

Another option is to explicitly construct the datetime.timedelta object. Since datetime.timedelta process negative hours, minutes etc., we can directly subtract the hours from the hours, the minutes from the minutes, etc. and the final output will have the correct time difference in seconds.

from datetime import timedelta

delta = timedelta(
    hours=t1.hour-t2.hour,
    minutes=t1.minute-t2.minute,
    seconds=t1.second-t2.second,
    microseconds=t1.microsecond-t2.microsecond
)                                               # <--- datetime.timedelta(seconds=38417)
diff_in_seconds = delta.total_seconds()         # 38417.0
diff_in_hours = delta.total_seconds() // 3600   # 10.0

Upvotes: 2

OldTinfoil
OldTinfoil

Reputation: 1215

It's because you cannot subtract a datetime.time from a datetime.time. Convert them to datetime.datetime objects and it'll return a datetime.timedelta object that you could use.

If you're lucky enough to be using Django 1.8, they now have a DurationField that can be used.

Failing that, I would recommend converting the timedelta into either seconds or a floating point representation so you can actually store it to the database.

EDIT: Pulled up in comments for half arsing an answer.

For example - if you want to store the number of (integer) seconds, you can convert from a TimeDelta by using secs = td // timedelta(seconds=1).

Upvotes: 16

Related Questions