как вычесть два значения datetime.time в шаблоне django, и как отформатировать длительность как часы, минуты - PullRequest
6 голосов
/ 15 августа 2011

В приложении 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)
...

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

Ответы [ 7 ]

6 голосов
/ 15 августа 2011

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

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

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 голосов
/ 16 августа 2011

Я не вижу, в чем проблема, кроме случая, когда время окончания будет позже, чем через 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 минут после старта

If
время начала 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
3 голосов
/ 04 марта 2014

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

{{ t2|timeuntil:t1 }}
2 голосов
/ 15 августа 2011

Представляет 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.Вы можете отформатировать его там как строку или использовать тег шаблона и т. Д.

1 голос
/ 16 августа 2011

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

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

1 голос
/ 15 августа 2011

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)
0 голосов
/ 15 августа 2011

Я бы, вероятно, просто добавил метод "duration" в вашу модель 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...