Формат Python timedelta в строку - PullRequest
       119

Формат Python timedelta в строку

226 голосов
/ 11 февраля 2009

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

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

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

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

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

Спасибо

Ответы [ 21 ]

185 голосов
/ 11 февраля 2009

Вы можете просто преобразовать 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
156 голосов
/ 12 февраля 2009

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

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

s = 13420
hours, remainder = divmod(s, 3600)
minutes, seconds = divmod(remainder, 60)
print '{:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds))
# result: 03:43:40

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

# 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 '{:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds))
# result: 03:43:40
55 голосов
/ 11 февраля 2009
>>> 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 части) и соединить ее вместе только с первыми 2 частями.

38 голосов
/ 07 декабря 2012
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)
            has_s = 's' if period_value > 1 else ''
            strings.append("%s %s%s" % (period_value, period_name, has_s))

    return ", ".join(strings)
27 голосов
/ 19 июня 2013

У него уже есть объект 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)

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

22 голосов
/ 17 ноября 2016

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

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

16 голосов
/ 30 января 2015

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

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

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

15 голосов
/ 10 января 2013

Опрашивающий хочет формат лучше, чем типичный:

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

возвращает результат в формате дд: чч: мм: сс:

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'
13 голосов
/ 29 октября 2009

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

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

span = currentdt - previousdt
print '%d,%d\n' % (span.days,span.seconds/3600)
12 голосов
/ 18 февраля 2017

Здесь представлена ​​функция общего назначения для преобразования объекта 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
...