1

I am pretty new to django and haven't been able to find a way to get the elapsed time between two DateTimeFields and save it to another model.

from django.db import models



class Timesheet(models.Model):
    startTime = models.DateTimeField(auto_now_add=True)
    endTime = models.DateTimeField(blank=True, null=True)
    duration = models.DateTimeField(endTime - startTime)

    def _str_(self):
        return self.startTime

How can I make duration = endTime - startTime? I am also using a PostgreSQL database.

3 Answers3

2

I wouldn't use a dedicated model field for the duration.

I would use a property on the model instead for the same functionality.

Something like:

@property
def duration(self)
    return self.end_time - self.startime

Lucas has a good idea of using an annotation, but if you have a Timesheet instance somewhere that didn't come from that object manager and was not previously annotated, you would have to do a separate database hit to actually annotate it.

This property is used as such:

some_timesheet_instance.duration
Art Vandelay
  • 183
  • 1
  • 9
1

Use annotate() to compute the duration field at query time for each object in the queryset

from django.db.models import F, ExpressionWrapper, fields    

timesheets = Timesheet.objects.annotate(
    duration=ExpressionWrapper(
        F('endTime') - F('startTime'),
        output_field=fields.DurationField()
    )
)

timesheets[0].duration  # datetime.timedelta(0, 722, 18373)

Is possible perform another queryset methods over annotations like filter(), order_by(), aggregate(), etc.

timesheets.order_by('-duration')  
timesheets.aggregate(Avg('duration')) # {'duration__avg': datetime.timedelta(0, 26473, 292625)} 
Lucas Weyne
  • 1,107
  • 7
  • 17
  • Where do I place this code? If I put it into my models.py I get an error saying Models aren't loaded yet. Does this go into my views or am I missing something? – Jaxson Mansouri Mar 13 '19 at 21:15
  • This code must be executed when you perform a query (don't put in your `models.py`), the `duration` field will be added at query-time – Lucas Weyne Mar 13 '19 at 21:23
0
duration = timesheet.end_time - timesheet.start_time

When you substract two datetime instances you don't get another datetime instance but a timedelta instace, which is just the days, seconds and microseconds difference between the two datetimes. You can't store a timedelta in a DateTimefield, but you can use an IntegerField, for example:

days_in_seconds = duration.days * 86400   # days difference by seconds in a day
duration_in_seconds = duration.seconds + days_in_seconds  # duration in seconds

When you want to access the duration as timedelta you just do:

import datetime

duration = datetime.timedelta(seconds=timesheet.duration)

You can also store it as FloatField as suggested in this question.

p14z
  • 1,760
  • 1
  • 11
  • 17