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

时间:2011-08-15 13:54:34

标签: python django filter

在django应用程序中,我向模板发送Entry个对象列表。每个Entry对象都有一个开始,结束时间是datetime.time值(来自TimeFields在列出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 个答案:

答案 0 :(得分:6)

你遇到了问题。你不能 - 也不应该 - 比较两次。是凌晨1点或凌晨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以将结果存储在数据库中以便于显示。

答案 1 :(得分:4)

我不知道问题出在哪里,除非结束时间晚于开始时间后24小时。

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

因此有两种情况:

  • 开始时间和结束时间可能相隔超过24小时,然后就像已经说过的那样,你必须转向使用datetime的对象

  • 要么在开始时间和结束时间之间总是少于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

以下代码仅用于更好地显示结果:

从日期时间导入时间

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

答案 2 :(得分:3)

您可以使用内置timedelta模板标记。 在django模板中,答案是:

{{ t2|timeuntil:t1 }}

答案 3 :(得分:2)

duration表示为模型中的属性:

from datetime import timedelta

@property
def duration(self):
    end = timedelta(self.endtime.hour, self.endtime.minute, self.endtime.second)
    start = timedelta(self.starttime.hour, self.starttime.minute, self.starttime.second)
    return end - start

返回timedelta对象。您可以将其格式化为字符串,或使用模板标签等。

答案 4 :(得分:1)

1:

可能不是,但你可以创建自己的标签,看看这个类似的代码: Timedelta template tag

2:

再一次,我找不到这样的东西。但是编写自定义标记应该很容易。 类似的东西:

def round_to_hours(minutes):
    return str(minutes/60) + ' hours and ' + str(minutes%60) + ' minutes'
register.filter(round_to_hours)

当然,这只是一个开始代码,还有很多需要改进的地方。

正如agf指出的那样,你可能需要一种方法来制作timedelta对象。 您可以尝试这样的事情(如果您可以假设两个时间都在同一天):

dummydate = datetime.date(1999,1,1)
delta = datetime.combine(dummydate, time1) - datetime.combine(dummydate, time2)

答案 5 :(得分:1)

也许这就是你要找的东西看看time_delta_total_seconds。如果您有复杂的事件调度要求,您可能希望使用lib。

http://code.google.com/p/django-swingtime/source/browse/swingtime/utils.py

答案 6 :(得分:0)

我可能只是在Entry模型中添加“持续时间”方法。 它很简单,直接,您可以像在任何其他模型字段{{entry.duration}}一样在模板中访问它。

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

    def duration(self):
        # perform duration calculation here
        return duration_display

答案 7 :(得分:0)

这也有帮助, 创建一个 python timedelta 对象。

from datetime import datetime
sub = datetime.strptime(str(start_time), "%H:%M:%S") - datetime.strptime(str(end_time), "%H:%M:%S")
# now `sub` is `datetime.timedelta`