djangotimedurationelapsed

Django - how to handle time duration


I am trying to display the elapsed time during a race.

class results(models.Model):
    race_id = models.ForeignKey(Race, on_delete=models.CASCADE)
    runner_id = models.ForeignKey(Runner, on_delete=models.CASCADE)
    race_start = models.DateTimeField()
    race_finish = models.DateTimeField(blank=True, null=True)
    obs = models.TextField(blank=True)
    def __str__(self):
        return self.race_id.race_cod+" - "+self.runner_id.name
    class Meta:
        verbose_name_plural = "Results"

Looking here I have found the following guides:

Django model elapsed time between two DateTimeFields

Django: What's the best field type to represent time elapsed?

Unfortunately, the solution presented there seems a little bit complex.

I also have found this workaround in the .html view page

<div class="info-box-content">
  <span class="info-box-number">Time - {{ results.race_finish|timesince:results.race_start }}</span>
</div>

the issue with this one is that everything over 24 hours came as x days, yy hours - while my need is to display the duration as HH:mm

Any hints here?


Solution

  • For this I would suggest adding a custom template filter or a new model property. For example, if you want to add this into your model:

    class results(models.Model):
        ...
        race_start = models.DateTimeField()
        race_finish = models.DateTimeField(blank=True, null=True)
        @property
        def duration(self):
            if not (self.race_start and self.race_finish): return None
            a,b=self.race_start, self.race_finish
            return '%s:%s' % ((b-a).days*24 + (b-a).seconds//3600, (b-a).seconds%3600//60)
    

    Here's an example converting it to a class (outside django) to show how it would work with two race times separated by 1 day, 2 hours, 17 minutes:

    import datetime
    class results:
        def __init__(self):
            self.race_start = datetime.datetime.now()
            self.race_finish = datetime.datetime.now() + datetime.timedelta(days=1, hours=2, minutes=17)
        @property
        def duration(self):
            if not (self.race_start and self.race_finish): return None
            a,b=self.race_start, self.race_finish
            return '%s:%s' % ((b-a).days*24 + (b-a).seconds//3600, (b-a).seconds%3600//60)
    
    >>> r=results()
    >>> r.duration
    '26:17'
    

    In other words, in your template, you can just have Time - {{ results.duration }} and it should show: "Time - 26:17".