如何在Django模板中减去两个datetime.time值,并将持续时间格式化为小时和分钟

7 投票
8 回答
12463 浏览
提问于 2025-04-16 23:37

在一个Django应用中,我把一系列Entry对象发送到模板。每个Entry对象都有开始和结束时间,这些时间是TimeFields表单中的datetime.time值。在列出这些Entry对象时,我需要显示每个条目的持续时间。因为开始和结束时间已经存在,所以在模型中添加一个持续时间字段似乎有些多余。

模型

class Entry(models.Model):
    title = models.CharField(unique=True,max_length=50)
    starttime=models.TimeField(null=True)
    endtime=models.TimeField(null=True)
...

模板

{% for entry in object_list %}
<tr> 
  <td> {{entry.title}} </td>
  <td> {{entry.starttime}}</td>
  <td> {{entry.endtime}}</td>
  <td> want to show duration here </td>
{%endfor %}

1.有没有什么过滤器可以接收两个datetime.time值,并计算出它们之间的持续时间(以秒为单位)?比如:

given
 t1=datetime.time(2,30,50) and
 t2=datetime.time(3,00,50)
should show
30 minutes

2.另外,有没有过滤器可以把持续时间以分钟为单位显示成小时和分钟,如果分钟数大于60的话?

比如:

if duration is 50 minutes ==> 50 minutes
if duration is 150 minutes ==> 2 hours,30 minutes

更新

def diff_in_time(start,end):
    startdelta=datetime.timedelta(hours=start.hour,minutes=start.minute,seconds=start.second)
    enddelta=datetime.timedelta(hours=end.hour,minutes=end.minute,seconds=end.second)
    return (enddelta-startdelta).seconds/60

当我尝试一些示例时间值时,得到了预期的结果。

#start 11:35:00 pm
#end   00:05:00 am
start= datetime.time(23,35,00)
end = datetime.time(00,05,00)
print diff_in_time(start,end)

==> 30 minutes

#start 00:35:00 am
#end   01:35:00 am
start= datetime.time(00,35,00)
end = datetime.time(01,35,00)
print diff_in_time(start,end)

==>60 minutes

8 个回答

4

你可以使用内置的 timedelta 模板标签。在 Django 模板中,答案会是:

{{ t2|timeuntil:t1 }}
6

你遇到了一个问题。你不能,也不应该,直接比较两个时间。比如说,晚上11点是比早上1点早,还是晚?这就要看它们是否在同一天了。

你需要把时间存储为 datetime 类型,或者其他能表示相对绝对时间的格式,或者像这样把它们转换成 datetime

def todatetime(time):
    return datetime.datetime.today().replace(hour=time.hour, minute=time.minute, second=time.second, 
                                             microsecond=time.microsecond, tzinfo=time.tzinfo)

def timestodelta(starttime, endtime):
    return todatetime(endtime) - todatetime(starttime)

如果你在跨越午夜的情况下调用 today 两次,这样做就会得不到你想要的结果。

在这种情况下,你可能应该使用这个应用程序中的 DurationField,它可以存储一个 timedelta,这样你就可以把结果存到数据库里,方便显示。

4

我看不出问题出在哪里,除了结束时间可能会比开始时间晚超过24小时的情况。

假设开始时间是9:00:00,结束时间是13:00:00。
如果这些时间是8月15日的9:00:00和8月17日的13:00:00,那么在不知道15号和17号的情况下,试图计算它们之间的时间差是没有意义的。

因此,有两种情况:

  • 要么开始时间和结束时间之间确实相隔超过24小时,那么就像之前说的,你需要使用日期时间对象。

  • 要么开始时间和结束时间之间始终少于24小时,那么问题就简单了。

==========================

让我们来看看第二种情况。

如果
开始时间是11:30:00
结束时间是12:35:00
那么结束时间显然是在开始时间之后的1小时5分钟

如果
开始时间是11:30:00
结束时间是10:35:00
那么结束时间不可能在同一天的早上早于开始时间,因此结束时间实际上是在开始时间的第二天早上,也就是24小时后。

同样的推理适用于开始时间在下午的情况,如果结束时间看起来在同一天的早上或下午早于开始时间,实际上结束时间是在第二天的早上或下午,具体取决于情况,但仍然是24小时后。

1)

所以一个小函数,只需要时间的属性就足够用来计算时间差:

def difft(start,end):
    a,b,c,d = start.hour, start.minute, start.second, start.microsecond
    w,x,y,z = end.hour, end.minute, end.second, end.microsecond
    delt = (w-a)*60 + (x-b) + (y-c)/60. + (z-d)/60000000
    return delt + 1440 if delt<0 else delt

以下代码只是为了更好地显示结果:

from datetime import time

def difft(start,end):
    a,b,c,d = start.hour, start.minute, start.second, start.microsecond
    w,x,y,z = end.hour, end.minute, end.second, end.microsecond
    delt = (w-a)*60 + (x-b) + (y-c)/60. + (z-d)/60000000

    D = '%sh %smn %ss %sms - %sh %smn %ss %sms == '
    ft = '%s + 1440 = %s  (1440 = 24x60mn)'
    return D % (w,x,y,z,a,b,c,d) +( ft % (delt, delt+1440) if delt<0 else str(delt))


print difft(time(11,30,0),time(12,35,0))
print difft(time(11,30,0),time(10,35,0))
print
print difft(time(20,40,0),time(22,41,0))
print difft(time(20,40,0),time(18,41,0))

结果

12h 35mn 0s 0ms - 11h 30mn 0s 0ms == 65.0
10h 35mn 0s 0ms - 11h 30mn 0s 0ms == -55.0 + 1440 = 1385.0  (1440 = 24x60mn)

22h 41mn 0s 0ms - 20h 40mn 0s 0ms == 121.0
18h 41mn 0s 0ms - 20h 40mn 0s 0ms == -119.0 + 1440 = 1321.0  (1440 = 24x60mn)

2)

为了以更易读的格式获取持续时间:

def difft2(start,end):
    a,b,c,d = start.hour, start.minute, start.second, start.microsecond
    w,x,y,z = end.hour, end.minute, end.second, end.microsecond
    delt = (w-a)*60 + (x-b) + (y-c)/60. + (z-d)/60000000.
    if delt < 0:
        delt += 1440

    hh,rem = divmod(delt,60)
    hh = int(hh)
    mm = int(rem)
    rem = (rem - mm)*60
    ss = int(rem)
    ms = (rem - ss)*1000000
    ms = int(ms)

    SS = '%sh %smn %ss %sms - %sh %smn %ss %sms == %sh %smn %ss %sms'
    return SS % (w,x,y,z,a,b,c,d,hh,mm,ss,ms)



print difft2(time(11,30,0),time(12,35,45,478129))
print difft2(time(11,30,45,11),time(10,35,45,12))
print
print difft2(time(20,40,0),time(22,41,0))
print difft2(time(20,40,0),time(18,41,0))

结果

12h 35mn 45s 478129ms - 11h 30mn 0s 0ms == 1h 5mn 45s 478128ms
10h 35mn 45s 12ms - 11h 30mn 45s 11ms == 23h 5mn 0s 1ms

22h 41mn 0s 0ms - 20h 40mn 0s 0ms == 2h 1mn 0s 0ms
18h 41mn 0s 0ms - 20h 40mn 0s 0ms == 22h 1mn 0s 0ms

撰写回答