как вычесть две даты.значения времени в шаблоне django и форматирование длительности в виде часа, минут

в приложении django я отправляю список Entry объекты шаблона.Каждый Entry объект имеет начальное, конечное время, которое является datetime.значения времени(с TimeFields на форме).При перечислении объектов записи мне нужно показать продолжительность для каждой записи.Ввод поля длительности в модель, казалось, был reduntant, так как время начала и окончания уже было

модель

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.есть ли какой-либо фильтр, который может возьмите две даты.значения времени и вычислить продолжительность в секундах. ie,

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

2.кроме того, есть фильтр, который может отображать продолжительность в заданном количестве минут как час, минут, если значение минут больше 60

ie,

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

7 ответов


Я не вижу, где проблема, кроме того, в случае, если время окончания будет позже, чем через 24 часа после начала.

предположим, что время начала-9: 00:00, а время окончания-13:00: 00
Если бы это время было принято 15 августа, 9: 00:00 и 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

следующий код предназначен только для лучшего отображения результата:

из datetime время импорт

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

у вас проблема. Вы не можете-и не должны-сравнивать два раза. 11 вечера до или после часа ночи? Это зависит от того, в один день они или нет.

вам нужно либо хранить их как datetime или что-то еще, что представляет собой относительно абсолютное время, или вам нужно превратить их в datetimes Вот так:

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 span полночь.

затем вы должны вероятно, используйте это приложение для DurationField, который хранит timedelta хранить результат в базе данных для удобства отображения.


представляют продолжительность как свойство на вашей модели:

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. Вы можете отформатировать его там, как строку, или использовать templatetag, и т. д.


вы можете использовать builtin timedelta - тег шаблона. В шаблоне django ответ будет:

{{ t2|timeuntil:t1 }}

1:

наверное, нет, но вы можете создать свой собственный тег, взгляните на этот код, который делает что-то подобное: тег шаблона Timedelta

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)

возможно, это то, что вы ищете посмотрите на time_delta_total_seconds. Вы можете использовать lib, если у вас есть сложные требования к планированию событий.

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


Я бы, вероятно, просто добавил метод "duration" к вашей модели ввода. Это легко, прямо вперед, и вы можете получить доступ к нему в шаблоне, как и к любому другому полю модели, {{entry.продолжительность.}}

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