Actuellement, je suis en train de consigner des données et j'utilise mon propre formateur avec un formatTime()
personnalisé:
def formatTime(self, _record, _datefmt):
t = datetime.datetime.now()
return t.strftime('%Y-%m-%d %H:%M:%S.%f')
Mon problème est que les microsecondes, %f
, sont six chiffres. Est-il possible de cracher moins de chiffres, comme les trois premiers chiffres des microsecondes?
Le moyen le plus simple serait d’utiliser le découpage en tranches pour couper les trois derniers chiffres des microsecondes:
def format_time():
t = datetime.datetime.now()
s = t.strftime('%Y-%m-%d %H:%M:%S.%f')
return s[:-3]
Si vous voulez réellement arrondir le nombre plutôt que de simplement couper, c'est un peu plus de travail mais pas 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:])
Cette méthode doit toujours renvoyer un horodatage qui ressemble exactement à ceci (avec ou sans le fuseau horaire, selon que l'objet dt
en entrée en contient un):
2016-08-05T18: 18: 54.776 + 0000
Il faut un objet datetime
en entrée (que vous pouvez produire avec datetime.datetime.now()
). Pour obtenir le fuseau horaire comme dans mon exemple de sortie, vous devez import pytz
et transmettre 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')
)
J'ai remarqué que certaines des méthodes ci-dessus omettaient le zéro final s'il en existait une (par exemple, 0.870
est devenu 0.87
) et cela posait problème à l'analyseur syntaxique dans lequel je chargeais ces horodatages. Cette méthode n'a pas ce problème.
Une solution simple qui devrait fonctionner dans tous les cas:
def format_time():
t = datetime.datetime.now()
if t.microsecond % 1000 >= 500: # check if there will be rounding up
t = t + datetime.timedelta(milliseconds=1) # manually round up
return t.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
Fondamentalement, vous commencez par arrondir manuellement l’objet de date lui-même, puis vous pouvez ajuster les microsecondes en toute sécurité.
Voici ma solution en utilisant regexp:
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())
Cette méthode permet une précision flexible et consomme toute la valeur en microsecondes si vous spécifiez une précision trop 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))
Cette méthode implémente l'arrondi à 3 décimales:
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)))
J'ai évité d'utiliser la méthode strftime
à dessein parce que je préférerais ne pas modifier un objet datetime entièrement sérialisé sans le revalider. Cette façon affiche également les dates internes au cas où vous souhaitez le modifier davantage.
Dans l'exemple d'arrondi, notez que la précision est basée sur une chaîne pour le module Decimal
.
Fixer la solution proposée sur Pablojim Commentaires:
from datetime import datetime
dt = datetime.now()
dt_round_microsec = round(dt.microsecond/1000) #number of zeroes to round
dt = dt.replace(microsecond=dt_round_microsec)