2012-06-14 33 views
22

Actualmente estoy registrando cosas y estoy usando mi propio formateador con un formatTime personalizado():pitón de fecha y hora: Redondo/número ajuste de dígitos en microsegundos

def formatTime(self, _record, _datefmt): 
     t = datetime.datetime.now() 
     return t.strftime('%Y-%m-%d %H:%M:%S.%f') 

Mi problema es que el microsegundos,% f, son seis dígitos ¿Hay alguna forma de escupir menos dígitos, como los primeros tres dígitos de los microsegundos?

Respuesta

27

La forma más sencilla sería utilizar rebanar a simplemente cortar los tres últimos dígitos de los microsegundos:

def format_time(): 
    t = datetime.datetime.now() 
    s = t.strftime('%Y-%m-%d %H:%M:%S.%f') 
    return s[:-3] 

Si desea realmente redondea el número en lugar de cortar, que es un poco más de trabajo, pero no es horrible:

def format_time(): 
    t = datetime.datetime.now() 
    s = t.strftime('%Y-%m-%d %H:%M:%S.%f') 
    tail = s[-7:] 
    f = round(float(tail), 3) 
    temp = "%.3f" % f 
    return "%s%s" % (s[:-7], temp[1:]) 
+0

Su método de redondeo no funciona para mí, se produce el siguiente resultado: '' 2015-04-12 17: 09: 020.588'', los segundos no son válidos. – NuclearPeon

+1

Probé tu código en python 2.7.6 y python 3.4.0. Copió y pegó su código, el mismo resultado cada vez. Tienes 3 dígitos en tu área de segundos. Estoy mirando el código y parece que tu flotación (variable 'f') se pega en el 0 que está delante del decimal (por ej .:' 0.367') que se agrega como una cadena. Ese 0 en el área de los segundos es donde comienza a fallar. – NuclearPeon

+2

@NuclearPeon Me disculpo. Identificó un error real, lo que prueba que en realidad no lo probé antes de publicarlo. He editado el código para corregir el error y debería funcionar para usted ahora. Gracias por traer esto a mi atención. – steveha

1

Este método permite una precisión flexible y consumirá el valor de microsegundos completo si especifica una precisión demasiado grande.

def formatTime(self, _record, _datefmt, precision=3): 
    dt = datetime.datetime.now() 
    us = str(dt.microsecond) 
    f = us[:precision] if len(us) > precision else us 
    return "%d-%d-%d %d:%d:%d.%d" % (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, int(f)) 

Este método implementa el redondeo a 3 decimales:

import datetime 
from decimal import * 

def formatTime(self, _record, _datefmt, precision='0.001'): 
    dt = datetime.datetime.now() 
    seconds = float("%d.%d" % (dt.second, dt.microsecond)) 
    return "%d-%d-%d %d:%d:%s" % (dt.year, dt.month, dt.day, dt.hour, dt.minute, 
          float(Decimal(seconds).quantize(Decimal(precision), rounding=ROUND_HALF_UP))) 

Me evitado usando el método strftime propósito porque yo preferiría no modificar un objeto de fecha y hora totalmente serializado sin revalidar ella. De esta forma, también se muestran los datos internos de la fecha en caso de que quiera modificarla más.

En el ejemplo de redondeo, tenga en cuenta que la precisión se basa en cadenas para el módulo Decimal.

2

En mi caso, estaba tratando de formatear una fecha con milisegundos formateada como 'ddd'. La solución que terminé usando para obtener milisegundos fue usar el atributo microsecond del objeto datetime, dividirlo por 1000.0, rellenarlo con ceros si fuera necesario y redondearlo con formato. Se ve así:

'{:03.0f}'.format(datetime.now().microsecond/1000.0) 
# Produces: '033', '499', etc. 
+0

microsegundo es 0 <= microsegundos <1000000. Así que exactamente para un millón producirá "1000". Esto es exactamente lo que me sucedió https://www.devrant.io/rants/466105 – alkuzad

+1

@alkuzad: Como mencionas, no puede ser exactamente un millón, pero 'format' lo redondeará a 1000 cuando el microsegundo sea al menos 999500 En lugar de redondear, puede agregar 500 microsegundos a la fecha y truncar para obtener el mismo efecto, mientras se ocupa automáticamente del redondeo a minutos, horas, días, meses o años. O simplemente truncar, si estar a medio milisegundo de distancia no le importa demasiado: '' {: 03} '. Format (datetime.now(). Microsecond // 1000) ' – Kundor

1

Este método siempre debe devolver una marca de tiempo que se ve exactamente como esta (con o sin la zona horaria en función de si el objeto de entrada dt contiene uno):

2016-08- 05T18: 18: 54.776 + 0000

Toma un objeto datetime como entrada (que puede producir con datetime.datetime.now()). Para obtener la zona horaria como en mi ejemplo de salida, necesitará import pytz y pasar datetime.datetime.now(pytz.utc).

import pytz, datetime 


time_format(datetime.datetime.now(pytz.utc)) 

def time_format(dt): 
    return "%s:%.3f%s" % (
     dt.strftime('%Y-%m-%dT%H:%M'), 
     float("%.3f" % (dt.second + dt.microsecond/1e6)), 
     dt.strftime('%z') 
    ) 

he notado que algunos de los otros métodos antes omitiría el cero de salida si había uno (por ejemplo 0.870 convirtió 0.87) y esto estaba causando problemas para el analizador I estaba alimentando estas marcas de tiempo en. Este método no tiene ese problema.

0

Aquí está mi solución usando expresiones regulares:

import re 

# Capture 6 digits after dot in a group. 
regexp = re.compile(r'\.(\d{6})') 
def to_splunk_iso(dt): 
    """Converts the datetime object to Splunk isoformat string.""" 
    # 6-digits string. 
    microseconds = regexp.search(dt.isoformat()).group(1) 
    return regexp.sub('.%d' % round(float(microseconds)/1000), dt.isoformat()) 
0

Otro enfoque basado en una solución elegante de John La Rooy

import math 

dt_round_sec = round(dt.microsecond/10**int(math.log10(dt.microsecond))+1)) 
dt = dt.replace(second=dt.second + dt_round_sec, microsecond=0) 
Cuestiones relacionadas