2011-12-06 27 views
19

Hola, necesito ayuda para entender por qué sucede esto. que tienen un método para realizar un seguimiento 'tiempo restante' en un programa de eventos:Python timedelta problema con valores negativos

def get_program_time_budget(self): 
    return self.estimated_duration-self.get_program_duration() 

Todo bien cuando el estimated_duration> self.get_program_duration() pero cuando esto va en sentido contrario las cosas se ponen divertido.

Los resultados se muestran al usuario:

Estimated 11 hours Allocated  10 hours 55 minutes  Remaining  5 minutes 

Cuando el resultado se vuelve negativa que tiene esto:

Estimated 11 hours Allocated  11 hours 5 minutes Remaining  -1 day 23 hours 55 minutes 

Alguna idea de cómo obtener el resultado -5 minutos?

EDIT: Aquí es el formateador timedelta (Tenga en cuenta que este es un filtro de Django, por lo que recibe el valor timedelta como str - pero se almacena como un timedelta):

def format_duration(value): 
    try: 
    delim = ':' 
    toks = value.split(',') 
    hour = minute = '' 
    d_string = value.count('day') and toks[0] or '' 
    h, m, s = d_string and toks[-1].strip().split(delim) or value.split(delim) 
    try: 
     hour = int(h) 
    except: 
     pass 
    try: 
     minute = int(m) 
    except: 
     pass 
    h_string = "%s%s%s" % (hour and hour or '', (hour and ' hour' or ''),(hour and hour > 1 and 's' or '') ) 
    m_string = "%s%s%s" % (minute and minute or '', (minute and ' minute' or ''),(minute and minute > 1 and 's' or '')) 
    return "%s %s %s" % (d_string, h_string, m_string) 
    except Exception, e: 
    logging.error("Error in format_duration -> %s. Duration value=%s" % (e, value)) 
    return ''v 
+1

This _is_ the way 'timedelta' funciona a valores negativos. Los resultados siempre se normalizan de modo que solo el valor de 'días' sea negativo. ¿Le gustaría negar los otros campos si el valor del día fuera, por ejemplo, -5? –

+3

Sabemos cómo restar dos timedeltas. Lo que no sabemos es qué código usó para mostrar el resultado. Para un mejor consejo, por favor divulgue. –

+1

Si quiere trabajar con valores de timedelta negativos de una manera sensata ("-1 minuto" es solo "-1 minuto" y ** no ** "-1 día más 23h59"), puede usar el módulo 'relativetimedelta' presente en [dateutil] (http://labix.org/python-dateutil). – florisla

Respuesta

35

Si está utilizando Python 2.7 o superior, puede usar timedelta.total_seconds() para obtener una representación de float del timedelta como una cantidad positiva o negativa de segundos.

>>> datetime.timedelta(-1, 86100).total_seconds() 
-300.0 

Debe ser capaz de usar esto para calcular una cantidad de minutos bastante fácil.

Si no está utilizando Python 2.7 se puede utilizar la siguiente fórmula equivalente de los documentos:

(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6)/10.0**6 

Editar: Parece que probablemente se está utilizando la representación de cadena por defecto para timedelta para mostrar el resultado , entonces mi respuesta original puede no ser tan útil. Yo sugeriría algo como esto para mostrar el resultado:

def get_program_time_budget(self): 
    td = self.estimated_duration-self.get_program_duration() 
    if td.days < 0: 
     return '-' + str(datetime.timedelta() - td) 
    return str(td) 

Esto ahora volvería una cadena en lugar de un timedelta, y por timedeltas negativos sería anteponer un '-' a un timedelta positivo.

+0

Gracias. Excelente respuesta pero no uso el formato str predeterminado. Tengo mi propio formateador (para quitar segundos, etc.), así que necesito un timedelta, no un str. Intentará la fórmula de los documentos para hacer total_segundos. –

+0

En ese caso, debe cambiar su formateador para convertirlo en un timedelta positivo y solo en un '-' al frente del mismo. –

+0

Desafortunadamente, el código del formateador es un filtro de Django, por lo que toma el timedelta .__ str__ (o __unicode__) como el valor - vea la pregunta del código. –

11

¿Por qué?

Posiblemente como un efecto secundario involuntario de la forma en que se definen // y %. Es posible que sea más fácil implementar la clase datetime. Cinco minutos antes de la época son las 23:55, no 0: -5.

Realmente no importa. Solo sepa que es como se normalizan days, seconds y microseconds. Y que se puede solucionar fácilmente.

def format_timedelta(td): 
    if td < timedelta(0): 
     return '-' + format_timedelta(-td) 
    else: 
     # Change this to format positive timedeltas the way you want 
     return str(td) 

>>> format_timedelta(timedelta(minutes=-5)) 
'-0:05:00' 
+2

Esto es tan simple y, sin embargo genio. ¡Gracias! –

Cuestiones relacionadas