2009-07-05 7 views
9

entiendo que segundos y microsegundos probablemente están representados por separado en datetime.timedelta por razones de eficiencia, pero que acabo de escribir esta función simple:Falta datetime.timedelta.to_seconds() -> float en Python?

def to_seconds_float(timedelta): 
    """Calculate floating point representation of combined 
    seconds/microseconds attributes in :param:`timedelta`. 

    :raise ValueError: If :param:`timedelta.days` is truthy. 

     >>> to_seconds_float(datetime.timedelta(seconds=1, milliseconds=500)) 
     1.5 
     >>> too_big = datetime.timedelta(days=1, seconds=12) 
     >>> to_seconds_float(too_big) # doctest: +ELLIPSIS 
     Traceback (most recent call last): 
     ... 
     ValueError: ('Must not have days', datetime.timedelta(1, 12)) 
    """ 
    if timedelta.days: 
     raise ValueError('Must not have days', timedelta) 
    return timedelta.seconds + timedelta.microseconds/1E6 

Esto es útil para cosas como pasar un valor a time.sleep o select.select. ¿Por qué no es algo así como esta parte de la interfaz datetime.timedelta? Me puede faltar un caso de esquina. La representación del tiempo parece tener tantos casos de esquina no obvios ...

Rechacé días para obtener una toma razonable con cierta precisión (soy demasiado vago para calcular el cajero automático matemático, así que esto parece un compromiso razonable ;-).

+0

¿Cuál es la pregunta? –

+0

Envalentonado, preguntándose si hay una razón por la que no está incluido en la interfaz. – cdleary

+2

Esto parece ser un duplicado de https://stackoverflow.com/questions/21414639/convert-timedelta-to-floating-point que tiene una mejor respuesta. – outofculture

Respuesta

12

Un flotador de Python tiene alrededor de 15 dígitos significativos, por lo que con segundos de hasta 86400 (5 dígitos a la izquierda del punto decimal) y microsegundos que necesitan 6 dígitos, puede incluir los días (hasta varios años)) sin pérdida de precisión.

Un buen mantra es "pi segundos es un nanocentro" - alrededor de 3.14E9 segundos por 100 años, es decir, 3E7 por año, por lo que 3E13 microsegundos por año. El mantra es bueno porque es memorable, aunque requiere que hagas un poco de aritmética mental después (pero, como las espinacas, es BUENO para ti, ¡te mantiene ágil y alerta!).

La filosofía de diseño de datetime es algo minimalista, por lo que no es sorprendente que omita muchos métodos de ayuda posibles que se reducen a simples expresiones aritméticas.

+0

Entiende que hay muchos * métodos de ayuda * posibles, pero este parece particularmente útil teniendo en cuenta las interfaces de otras funciones stdlib: ¿cree que vale la pena proponer para su inclusión? Será tu llamada de todos modos. ;-) – cdleary

+0

Honestamente, ya no dedico tiempo a los hilos de los cientos de posts en python-dev, se ha vuelto demasiado lento :-(. Sugiero que vaya a python-ideas y pruebe armar un PEP con un conjunto de métodos extra de ayuda que pueden resultar populares y no controversiales (mi favorito sería un método de marca de tiempo total - ¡tener solo de la marca de tiempo es absurdo!), luego al aire en python-dev y - * duck * ! -) –

+0

Debería votar por el comentario de espinacas. :) Me gusta el mantra por cierto, así que voté en su lugar. – Scott

3

Su preocupación por la precisión está fuera de lugar. He aquí un sencillo de dos-liner para calcular aproximadamente cuántos años se puede exprimir en lo que queda de los 53 bits de precsion en un IEEE754 64 bits float:

>>> import math 
>>> 10 ** (math.log10(2 ** 53) - math.log10(60 * 60 * 24) - 6)/365.25 
285.42092094268787 
>>> 

Cuidado con redondeo; agregue los números más pequeños que no sean cero primero:

return timedelta.seconds + timedelta.microseconds/1E6 + timedelta.days * 86400 
+0

No estoy seguro de que esté fuera de lugar, incluso sabiendo esto, ahora debe determinar si es preferible permitir un número de días <= 285 (que es un número de restricción bastante raro para las personas) que rechazarlos como regla (Fácil de recordar). Gracias por haberlo calculado, ese es el trabajo que esperaba evitar en primer lugar. :-) – cdleary

+0

El punto de mi respuesta fue que todavía se puede tener una precisión de microsegundos si se agregan en 280 años impares. Sin embargo, las personas que trabajan con años probablemente no se preocupen por microsegundos de todos modos. ¿Qué restricción?Seguramente no planeabas verificar durante 285 años en tu código. Sheesh * 2 ** 53 !! Si el timedelta es decir 300 * 366 días y los segundos y microsegundos son cero, no se perderá precisión. Recuerde que F es la abreviatura de Flotante, no Fijo. –

+0

Entiendo, solo pensé que calcular si la precisión era suficiente sobre la marcha era significativamente más complicado que limitarlo en la dimensión más significativa. (También es más fácil saber cómo arreglar la condición de error.) Sin embargo, creo que tienes razón: si quería hacer que esta función fuera más seria, podría generar un ValueError al determinar que no podía cumplir con la precisión requerida y dejar que el usuario se ocupa de eso desde allí. – cdleary

Cuestiones relacionadas