Формат Python timedelta для строки

Я новичок Python (2 недели), и у меня возникли проблемы с форматированием объекта datetime.timedelta .

Вот что я пытаюсь сделать: у меня есть список объектов, и один из членов класса объекта – объект timedelta, который показывает продолжительность события. Я хотел бы показать эту продолжительность в формате часов: минут.

Я пробовал различные методы для этого, и у меня возникают трудности. Мой текущий подход заключается в том, чтобы добавлять методы в класс для моих объектов, которые возвращают часы и минуты. Я могу получить часы, разделив timedelta.seconds на 3600 и округляя его. У меня возникли проблемы с получением оставшихся секунд и преобразованием их в минуты.

Кстати, я использую Google AppEngine с Google AppEngine Django Templates для презентации.

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

Благодаря,

18 Solutions collect form web for “Формат Python timedelta для строки”

Вы можете просто преобразовать timedelta в строку с помощью str (). Вот пример:

 import datetime start = datetime.datetime(2009,2,10,14,00) end = datetime.datetime(2009,2,10,16,00) delta = end-start print str(delta) # prints 2:00:00 

Как вы знаете, вы можете получить секунды от объекта timedelta, обратившись к .seconds .

Вы можете преобразовать это в часы и остатки, используя комбинацию по модулю и вычитанию:

 # arbitrary number of seconds s = 13420 # hours hours = s // 3600 # remaining seconds s = s - (hours * 3600) # minutes minutes = s // 60 # remaining seconds seconds = s - (minutes * 60) # total time print '%s:%s:%s' % (hours, minutes, seconds) # result: 3:43:40 

Тем не менее, python предоставляет встроенную функцию divmod (), которая позволяет нам упростить этот код:

 s = 13420 hours, remainder = divmod(s, 3600) minutes, seconds = divmod(remainder, 60) print '%s:%s:%s' % (hours, minutes, seconds) # result: 3:43:40 

Надеюсь это поможет!

 >>> str(datetime.timedelta(hours=10.56)) 10:33:36 >>> td = datetime.timedelta(hours=10.505) # any timedelta object >>> ':'.join(str(td).split(':')[:2]) 10:30 

Передача объекта timedelta функции str() вызывает тот же код форматирования, который используется, если мы просто напечатаем print td . Поскольку вы не хотите секунд, мы можем разделить строку на двоеточия (3 части) и вернуть их вместе только с первыми двумя частями.

 def td_format(td_object): seconds = int(td_object.total_seconds()) periods = [ ('year', 60*60*24*365), ('month', 60*60*24*30), ('day', 60*60*24), ('hour', 60*60), ('minute', 60), ('second', 1) ] strings=[] for period_name,period_seconds in periods: if seconds > period_seconds: period_value , seconds = divmod(seconds,period_seconds) if period_value == 1: strings.append("%s %s" % (period_value, period_name)) else: strings.append("%s %ss" % (period_value, period_name)) return ", ".join(strings) 

У него уже есть объект timedelta, поэтому почему бы не использовать его встроенный метод total_seconds (), чтобы преобразовать его в секунды, а затем использовать divmod (), чтобы получить часы и минуты?

 hours, remainder = divmod(myTimeDelta.total_seconds(), 3600) minutes, seconds = divmod(remainder, 60) # Formatted only for hours and minutes as requested print '%s:%s' % (hours, minutes) 

Это работает независимо от того, имеет ли дельта времени даже дни или годы.

Мои объекты datetime.timedelta больше суток. Итак, вот еще одна проблема. Все вышеприведенное обсуждение предполагает менее одного дня. timedelta на самом деле является кортежем дней, секунд и микросекунд. Вышеупомянутое обсуждение должно использовать td.seconds как joe, но если у вас есть дни, он НЕ включен в значение секунд.

Я получаю промежуток времени между 2 датами и печать дней и часов.

 span = currentdt - previousdt print '%d,%d\n' % (span.days,span.seconds/3600) 

Вопросник требует более приятного формата, чем типичный:

  >>> import datetime >>> datetime.timedelta(seconds=41000) datetime.timedelta(0, 41000) >>> str(datetime.timedelta(seconds=41000)) '11:23:20' >>> str(datetime.timedelta(seconds=4102.33)) '1:08:22.330000' >>> str(datetime.timedelta(seconds=413302.33)) '4 days, 18:48:22.330000' 

Итак, на самом деле есть два формата, один из которых равен 0, а он отсутствует, а другой – текст «n дней, h: m: s». Но секунды могут иметь доли, и в распечатках нет нулевых нулей, поэтому столбцы беспорядочны.

Вот моя рутина, если вам это нравится:

 def printNiceTimeDelta(stime, etime): delay = datetime.timedelta(seconds=(etime - stime)) if (delay.days > 0): out = str(delay).replace(" days, ", ":") else: out = "0:" + str(delay) outAr = out.split(':') outAr = ["%02d" % (int(float(x))) for x in outAr] out = ":".join(outAr) return out 

это возвращает выход как dd: hh: mm: ss format:

 00:00:00:15 00:00:00:19 02:01:31:40 02:01:32:22 

Я подумал о том, чтобы добавить годы к этому, но это остается как упражнение для читателя, так как выход безопасен более 1 года:

 >>> str(datetime.timedelta(seconds=99999999)) '1157 days, 9:46:39' 

Я знаю, что это старый ответ, но для этого я использую datetime.utcfromtimestamp() . Он занимает несколько секунд и возвращает datetime которое может быть отформатировано, как и любое другое время.

 duration = datetime.utcfromtimestamp(end - begin) print duration.strftime('%H:%M') 

Если вы останетесь в правовых диапазонах для временных частей, это должно работать, то есть оно не возвращает 1234: 35, так как часы <= 23.

Я лично использую библиотеку humanize для этого:

 >>> import datetime >>> humanize.naturalday(datetime.datetime.now()) 'today' >>> humanize.naturalday(datetime.datetime.now() - datetime.timedelta(days=1)) 'yesterday' >>> humanize.naturalday(datetime.date(2007, 6, 5)) 'Jun 05' >>> humanize.naturaldate(datetime.date(2007, 6, 5)) 'Jun 05 2007' >>> humanize.naturaltime(datetime.datetime.now() - datetime.timedelta(seconds=1)) 'a second ago' >>> humanize.naturaltime(datetime.datetime.now() - datetime.timedelta(seconds=3600)) 'an hour ago' 

Конечно, он не дает вам точно ответ, который вы искали (это, действительно, str(timeA - timeB) , но я обнаружил, что, как только вы выходите за пределы нескольких часов, дисплей становится быстро нечитаемым. поддержка гораздо больших значений, которые удобочитаемы для человека, а также хорошо локализованы.

По-видимому, это contrib.humanize модулем contrib.humanize от Django, так как вы используете Django, вам, вероятно, следует это использовать.

Следуя приведенному выше примеру Джо, я бы использовал оператор арифметики модуля, таким образом:

 td = datetime.timedelta(hours=10.56) td_str = "%d:%d" % (td.seconds/3600, td.seconds%3600/60) 

Обратите внимание, что целочисленное деление в Python округляется по умолчанию; если вы хотите быть более явным, используйте math.floor () или math.ceil (), если это необходимо.

Я бы всерьез рассмотрел подход Бритвы Оккама:

 td = str(timedelta).split('.')[0] 

Это возвращает строку без микросекунд

Если вы хотите восстановить объект datetime.timedelta, просто выполните следующее:

 h,m,s = re.split(':', td) new_delta = datetime.timedelta(hours=int(h),minutes=int(m),seconds=int(s)) 

2 года, я люблю этот язык!

Здесь используется функция общего назначения для преобразования объекта timedelta или обычного числа (в виде секунд или минут и т. Д.) В красиво отформатированную строку. Я воспринял фантастический ответ mpounsett по дублирующему вопросу, сделал его немного более гибким, улучшенным читабельностью и добавила документацию.

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

  1. Настройте формат строки «на лету» вместо жесткого кодирования.
  2. Оставьте определенные промежутки времени без проблем (см. Примеры ниже).

Функция:

 from string import Formatter from datetime import timedelta def strfdelta(tdelta, fmt='{D:02}d {H:02}h {M:02}m {S:02}s', inputtype='timedelta'): """Convert a datetime.timedelta object or a regular number to a custom- formatted string, just like the stftime() method does for datetime.datetime objects. The fmt argument allows custom formatting to be specified. Fields can include seconds, minutes, hours, days, and weeks. Each field is optional. Some examples: '{D:02}d {H:02}h {M:02}m {S:02}s' --> '05d 08h 04m 02s' (default) '{W}w {D}d {H}:{M:02}:{S:02}' --> '4w 5d 8:04:02' '{D:2}d {H:2}:{M:02}:{S:02}' --> ' 5d 8:04:02' '{H}h {S}s' --> '72h 800s' The inputtype argument allows tdelta to be a regular number instead of the default, which is a datetime.timedelta object. Valid inputtype strings: 's', 'seconds', 'm', 'minutes', 'h', 'hours', 'd', 'days', 'w', 'weeks' """ # Convert tdelta to integer seconds. if inputtype == 'timedelta': remainder = int(tdelta.total_seconds()) elif inputtype in ['s', 'seconds']: remainder = int(tdelta) elif inputtype in ['m', 'minutes']: remainder = int(tdelta)*60 elif inputtype in ['h', 'hours']: remainder = int(tdelta)*3600 elif inputtype in ['d', 'days']: remainder = int(tdelta)*86400 elif inputtype in ['w', 'weeks']: remainder = int(tdelta)*604800 f = Formatter() desired_fields = [field_tuple[1] for field_tuple in f.parse(fmt)] possible_fields = ('W', 'D', 'H', 'M', 'S') constants = {'W': 604800, 'D': 86400, 'H': 3600, 'M': 60, 'S': 1} values = {} for field in possible_fields: if field in desired_fields and field in constants: values[field], remainder = divmod(remainder, constants[field]) return f.format(fmt, **values) 

Демоверсия:

 >>> td = timedelta(days=2, hours=3, minutes=5, seconds=8, microseconds=340) >>> print strfdelta(td) 02d 03h 05m 08s >>> print strfdelta(td, '{D}d {H}:{M:02}:{S:02}') 2d 3:05:08 >>> print strfdelta(td, '{D:2}d {H:2}:{M:02}:{S:02}') 2d 3:05:08 >>> print strfdelta(td, '{H}h {S}s') 51h 308s >>> print strfdelta(12304, inputtype='s') 00d 03h 25m 04s >>> print strfdelta(620, '{H}:{M:02}', 'm') 10:20 >>> print strfdelta(49, '{D}d {H}h', 'h') 2d 1h 
 def seconds_to_time_left_string(total_seconds): s = int(total_seconds) years = s // 31104000 if years > 1: return '%d years' % years s = s - (years * 31104000) months = s // 2592000 if years == 1: r = 'one year' if months > 0: r += ' and %d months' % months return r if months > 1: return '%d months' % months s = s - (months * 2592000) days = s // 86400 if months == 1: r = 'one month' if days > 0: r += ' and %d days' % days return r if days > 1: return '%d days' % days s = s - (days * 86400) hours = s // 3600 if days == 1: r = 'one day' if hours > 0: r += ' and %d hours' % hours return rs = s - (hours * 3600) minutes = s // 60 seconds = s - (minutes * 60) if hours >= 6: return '%d hours' % hours if hours >= 1: r = '%d hours' % hours if hours == 1: r = 'one hour' if minutes > 0: r += ' and %d minutes' % minutes return r if minutes == 1: r = 'one minute' if seconds > 0: r += ' and %d seconds' % seconds return r if minutes == 0: return '%d seconds' % seconds if seconds == 0: return '%d minutes' % minutes return '%d minutes and %d seconds' % (minutes, seconds) for i in range(10): print pow(8, i), seconds_to_time_left_string(pow(8, i)) Output: 1 1 seconds 8 8 seconds 64 one minute and 4 seconds 512 8 minutes and 32 seconds 4096 one hour and 8 minutes 32768 9 hours 262144 3 days 2097152 24 days 16777216 6 months 134217728 4 years 

У меня была аналогичная проблема с выводом расчета сверхурочных на работу. Значение должно всегда отображаться в HH: MM, даже если оно больше одного дня, и значение может стать отрицательным. Я объединил некоторые из представленных решений, и, возможно, кто-то еще найдет это решение полезным. Я понял, что если значение timedelta отрицательно, большинство представленных решений с использованием метода divmod не работают из коробки:

 def td2HHMMstr(td): '''Convert timedelta objects to a HH:MM string with (+/-) sign''' if td < datetime.timedelta(seconds=0): sign='-' td = -td else: sign = '' tdhours, rem = divmod(td.total_seconds(), 3600) tdminutes, rem = divmod(rem, 60) tdstr = '{}{:}:{:02d}'.format(sign, int(tdhours), int(tdminutes)) return tdstr 

timedelta to HH: MM string:

 td2HHMMstr(datetime.timedelta(hours=1, minutes=45)) '1:54' td2HHMMstr(datetime.timedelta(days=2, hours=3, minutes=2)) '51:02' td2HHMMstr(datetime.timedelta(hours=-3, minutes=-2)) '-3:02' td2HHMMstr(datetime.timedelta(days=-35, hours=-3, minutes=-2)) '-843:02' 
 from django.utils.translation import ngettext def localize_timedelta(delta): ret = [] num_years = int(delta.days / 365) if num_years > 0: delta -= timedelta(days=num_years * 365) ret.append(ngettext('%d year', '%d years', num_years) % num_years) if delta.days > 0: ret.append(ngettext('%d day', '%d days', delta.days) % delta.days) num_hours = int(delta.seconds / 3600) if num_hours > 0: delta -= timedelta(hours=num_hours) ret.append(ngettext('%d hour', '%d hours', num_hours) % num_hours) num_minutes = int(delta.seconds / 60) if num_minutes > 0: ret.append(ngettext('%d minute', '%d minutes', num_minutes) % num_minutes) return ' '.join(ret) 

Это даст:

 >>> from datetime import timedelta >>> localize_timedelta(timedelta(days=3660, minutes=500)) '10 years 10 days 8 hours 20 minutes' 

Проверьте эту функцию – она ​​преобразует объект timedelta в строку «HH: MM: SS»

 def format_timedelta(td): hours, remainder = divmod(td.total_seconds(), 3600) minutes, seconds = divmod(remainder, 60) hours, minutes, seconds = int(hours), int(minutes), int(seconds) if hours < 10: hours = '0%s' % int(hours) if minutes < 10: minutes = '0%s' % minutes if seconds < 10: seconds = '0%s' % seconds return '%s:%s:%s' % (hours, minutes, seconds) 
 t1 = datetime.datetime.strptime(StartTime, "%H:%M:%S %d-%m-%y") t2 = datetime.datetime.strptime(EndTime, "%H:%M:%S %d-%m-%y") return str(t2-t1) 

Таким образом, для:

 StartTime = '15:28:53 21-07-13' EndTime = '15:32:40 21-07-13' 

возвращает:

 '0:03:47' 

Спасибо всем за вашу помощь. Я взял много ваших идей и собрал их вместе, дайте мне знать, что вы думаете.

Я добавил два метода в класс следующим образом:

 def hours(self): retval = "" if self.totalTime: hoursfloat = self.totalTime.seconds / 3600 retval = round(hoursfloat) return retval def minutes(self): retval = "" if self.totalTime: minutesfloat = self.totalTime.seconds / 60 hoursAsMinutes = self.hours() * 60 retval = round(minutesfloat - hoursAsMinutes) return retval 

В моем django я использовал это (сумма – это объект, и он находится в словаре):

 <td>{{ sum.0 }}</td> <td>{{ sum.1.hours|stringformat:"d" }}:{{ sum.1.minutes|stringformat:"#02.0d" }}</td> 
  • Подсчет числа дней недели между двумя датами
  • Проблема Python timedelta с отрицательными значениями
  • TypeError: не может сравнивать datetime.timedelta для float
  • поведение python timedelta при вычитании
  • Python: получить datetime для «3 лет назад сегодня»?
  • python: какой файл более новый и на сколько времени
  • Python timedelta удаляет микросекунды
  • Python: учитывая дату и день недели, найдите дату следующего появления заданного рабочего дня
  • вычислять разницу в времени и времени в годах, месяцах и т. д. в новой колонке данных pandas
  • Как добавить delta в python datetime.time?
  • Преобразование timedelta в плавающую точку
  • Python - лучший язык программирования в мире.