开发者

how to substract two datetime.time values in django template,and how to format a duration as hour,minutes

In a django app ,I am sending a list of Entry objects to the template.Each Entry object has a start, end times which are datetime.time values(from TimeFields on the form).While listing the Entry objects,I need to show the duration for each entry.Putting a duration field in model seemed to be reduntant since ,start and end times were already there

model

class Entry(models.Model):
    title = models.CharField(unique=True,max_length=开发者_运维知识库50)
    starttime=models.TimeField(null=True)
    endtime=models.TimeField(null=True)
...

template

{% 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.Is there any filter which can take two datetime.time values and calculate the duration in seconds. ie,

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

2.Also,is there a filter,that can show a duration in given number of minutes as hour,minutes if the minutes value is greater than 60

ie,

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

update

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

when i tried with some sample time values ,it gave me the expected result

#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


You've got a problem. You can't -- and shouldn't be able to -- compare two times. Is 11pm before or after 1am? It depends whether or not they're on the same day.

You need to either store them as datetime or something else that represents a relatively absolute time, or you need to turn them into datetimes like this:

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)

This will fail to give the expected answer if the two calls to today span midnight.

Then you should probably use this app for a DurationField which stores a timedelta to store the result in the database for easy display.


I don't see where is the problem, apart in case the end-time would be later than 24 hours after the start-time.

Suppose that start-time is 9:00:00 and end-time is 13:00:00
If these times were taken on August 15, 9:00:00 and August 17, 13:00:00 , there would be no sense to try to obtain the time delta between them without knowing the days 15 and 17.

Hence there are two cases:

  • either the start time and end time may be really separated by more than 24 hours , then as it has already been said, you must move to the use of datetime's objects

  • either there is always less than 24 hours between the start-time and the end-time, then the problem is simple.

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

Let us examine the second case.

If
start-time 11:30:00
end-time.. 12:35:00
The end is evidently 1 hour 5 minutes after the start

If
start-time 11:30:00
end-time.. 10:35:00
The end can't be before the start in the same morning, then the end is in fact in the morning of the next day after the day in which is the start, that is to say 24 hours later.

The same reasoning applies when the start is in the afternoon and the end time is apparently before the start time in the same day, in afternoon or morning: end time is in fact in the the next day, morning or afternoon, it depends but it's still 24 hours later.

1)

So a little function, that need only the attributes of the times is sufficient to deduct the time difference:

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

The following code is only for a better display of the result:

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))

result

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)

To obtain the durations in a more readable format:

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))

result

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


You can use builtin timedelta template tag. In django template answer would be:

{{ t2|timeuntil:t1 }}


Represent duration as a property on your model:

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

Which returns a timedelta object. You can format it there as a string, or use a templatetag, etc.


1:

Probably not, but you could create your own tag, take a look at this code that does something similar: Timedelta template tag

2:

Again, i couldnt find anything like this. But it should be easy to code a custom tag to do it. Something like:

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

Of course, this is just a start code, There's much to improve.

As agf pointed out, you'll probably need a way to make timedelta objects. You could try something like this (if you can assume both times are on the same day):

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


Perhaps this is what you are looking for Look at the time_delta_total_seconds. You might like to use the lib if you have complicated event scheduling requirements.

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


I would probably just add a "duration" method to your Entry model. It's easy, straight forward, and you can access it in the template like any other model field, {{ 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


this could help too, creating a python timedelta object.

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` 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜