Formatear timedelta a cadena

Resuelto mawcs asked hace 15 años • 35 respuestas

Tengo problemas para formatear undatetime.timedelta objeto.

Esto es lo que intento hacer: tengo una lista de objetos y uno de los miembros de la clase del objeto es un objeto timedelta que muestra la duración de un evento. Me gustaría mostrar esa duración en el formato de horas:minutos.

He probado varios métodos para hacer esto y tengo dificultades. Mi enfoque actual es agregar métodos a la clase para mis objetos que devuelven horas y minutos. Puedo obtener las horas dividiendo el timedelta.segundos por 3600 y redondeándolo. Tengo problemas para obtener los segundos restantes y convertirlos a minutos.

Por cierto, estoy usando Google AppEngine con Django Templates para la presentación.

mawcs avatar Feb 12 '09 03:02 mawcs
Aceptado

Puedes convertir el timedelta en una cadena con str(). He aquí un ejemplo:

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
Parand avatar Feb 11 '2009 20:02 Parand

Como sabes, puedes obtener el total_segundos de un objeto timedelta accediendo al .secondsatributo.

Python proporciona la función incorporada divmod()que permite:

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

o puedes convertir a horas y resto usando una combinación de módulo y resta:

# 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
John Fouhy avatar Feb 11 '2009 23:02 John Fouhy
>>> 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

Pasar el timedeltaobjeto a la str()función llama al mismo código de formato que se usa si simplemente escribimos print td. Como no quieres los segundos, podemos dividir la cadena por dos puntos (3 partes) y volver a juntarla con solo las primeras 2 partes.

joeforker avatar Feb 11 '2009 20:02 joeforker

Aquí hay una función de propósito general para convertir un timedeltaobjeto o un número normal (en forma de segundos o minutos, etc.) en una cadena con un buen formato. Tomé la fantástica respuesta de mpounsett a una pregunta duplicada, la hice un poco más flexible, mejoré la legibilidad y agregué documentación.

Descubrirá que es la respuesta más flexible hasta el momento, ya que le permite:

  1. Personalice el formato de cadena sobre la marcha en lugar de codificarlo.
  2. Omita ciertos intervalos de tiempo sin problema (ver ejemplos a continuación).

Función:

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)

Manifestación:

>>> 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
MarredCheese avatar Feb 18 '2017 20:02 MarredCheese