100 votes

<div> datetime: Arrondi / couper le nombre de chiffres dans les microsecondes </div>

Actuellement, je consigne des informations et j'utilise mon propre formateur avec une formatTime() personnalisée :

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 n'afficher que trois chiffres, comme les premiers trois chiffres des microsecondes ?

4voto

Apteryx Points 4279

Modification : Comme certains l'ont souligné dans les commentaires ci-dessous, l'arrondi de cette solution (et celle ci-dessus) pose problème lorsque la valeur de microseconde atteint 999500, car 999,5 est arrondi à 1000 (dépassement).

À moins de réimplémenter strftime pour supporter le format que nous voulons (le dépassement potentiel causé par l'arrondi devrait être propagé jusqu'aux secondes, puis aux minutes, etc.), il est beaucoup plus simple de simplement tronquer aux 3 premiers chiffres comme décrit dans la réponse acceptée, ou en utilisant quelque chose comme :

'{:03}'.format(int(999999/1000))

-- Réponse originale conservée ci-dessous --

Dans mon cas, je cherchais à formater un horodatage avec des millisecondes formatées en 'ddd'. La solution que j'ai fini par utiliser pour obtenir les millisecondes était d'utiliser l'attribut microseconde de l'objet datetime, le diviser par 1000.0, le compléter de zéros si nécessaire, et l'arrondir avec format. Cela ressemble à ceci :

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

2voto

iurii Points 1579

Voici ma solution en utilisant regexp:

import re

# Capture 6 chiffres après le point dans un groupe.
regexp = re.compile(r'\.(\d{6})')
def to_splunk_iso(dt):
    """Convertit l'objet datetime en une chaîne de format iso Splunk."""
    # Chaîne de 6 chiffres.
    microseconds = regexp.search(dt.isoformat()).group(1)
    return regexp.sub('.%d' % round(float(microseconds) / 1000), dt.isoformat())

2voto

fpeelo Points 342

Steveha a déjà dit qu'il faut tronquer. Cela vous arrondira à la baisse. Mais si vous voulez arrondir au chiffre le plus proche, la manière d'arrondir les nombres en général est d'ajouter 5 à l'endroit des décimales que vous couperiez, avant de procéder à la troncature. Par exemple, pour arrondir 12,3456 à 3 décimales, ajoutez 0,0005; cela vous donne 12,3461 que vous tronquez ensuite à 3 caractères après le point, vous donnant ainsi 12,346.

La question est, comment ajouter 5 au prochain endroit des décimales - correctement. Ainsi, vous ne pouvez pas simplement considérer les microsecondes, si vous arrondissez .9995 secondes alors qu'il est juste avant minuit du réveillon du Nouvel An, la retenue pourrait remonter jusqu'à l'année!

Mais vous pouvez utiliser un timedelta. Ensuite, le calcul du temps est correct et vous pouvez simplement tronquer pour obtenir votre valeur correctement arrondie.

Pour arrondir à 3 décimales en secondes, vous voulez ajouter 0,0005 secondes = 500 microsecondes. Voici 3 exemples: tout d'abord, arrondir 0,1234 secondes à 0,123, puis arrondir 0,1235 secondes à 0,124, puis la retenue se propage tout le chemin lorsque vous devriez embrasser quelqu'un pour lui souhaiter une bonne année et au lieu de cela vous faites du Python:

>>> r = datetime.timedelta(microseconds=500)
>>> t = datetime.datetime(2023,1,2,3,45,6,123456)
>>> (t+r).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
'2023-01-02 03:45:06.123'
>>> t = datetime.datetime(2023,1,2,3,45,6,123556)
>>> (t+r).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
'2023-01-02 03:45:06.124'
>>> t = datetime.datetime(2023,12,31,23,59,59,999500)
>>> (t+r).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
'2024-01-01 00:00:00.000'

1voto

NuclearPeon Points 547

Cette méthode permet une précision flexible et consommera la valeur entière des microsecondes si vous spécifiez une trop grande précision.

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 délibérément car je préférerais ne pas modifier un objet datetime entièrement sérialisé sans le révalider. Cette méthode montre également les détails de la date au cas où vous souhaiteriez la modifier davantage.

Dans l'exemple d'arrondi, notez que la précision est basée sur des chaînes pour le module Decimal.

1voto

Tao Starbow Points 334

Je cherchais le format : '2023-10-19T18:12:44.884Z' Après avoir lu les suggestions sur la page, j'ai pu obtenir ce que je voulais en une seule ligne :

f"{now.strftime('%Y-%m-%dT%H:%M:%S')}.{str(now.microsecond)[:3]}Z"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X