HOWTO · Python

Convertir un datetime de Python a string con milisegundos

Convierte un datetime de Python en una cadena ISO o personalizada con exactamente tres dígitos de milisegundos.

En esta página

Usa value.isoformat(timespec="milliseconds") cuando un resultado de estilo ISO sea adecuado. Usa strftime() con %f y elimina sus tres últimos dígitos cuando necesites un diseño personalizado. Ambos enfoques truncan los microsegundos a milisegundos en lugar de redondearlos.

El formato cambia la representación, no el valor datetime en sí. Los ejemplos usan entradas fijas para que la salida pueda verificarse exactamente; reemplaza esos constructores con un valor de tu aplicación después de elegir el diseño requerido. Si el sistema receptor espera un desplazamiento, haz que el valor tenga zona horaria antes de formatearlo.

Usa isoformat() para precisión de milisegundos de tres dígitos

datetime.isoformat() es la opción más clara para una cadena de estilo ISO 8601. El argumento timespec="milliseconds" siempre emite exactamente tres dígitos fraccionarios de segundo. Está disponible en Python 3.6 y versiones posteriores.

Pasa exactamente la cadena plural en minúsculas "milliseconds". Otros valores admitidos de timespec seleccionan niveles de precisión distintos, mientras que un valor desconocido genera ValueError. Este parámetro explícito es preferible al comportamiento predeterminado "auto" cuando un esquema posterior requiere un ancho de campo constante.

El siguiente ejemplo determinista usa un datetime consciente de zona horaria, por lo que el resultado también muestra que isoformat() conserva el desplazamiento UTC:

"""Show the recommended ISO-style millisecond formatting behavior."""

from datetime import datetime, timezone


value = datetime(2026, 9, 16, 12, 34, 56, 789654, tzinfo=timezone.utc)
print(value.isoformat(timespec="milliseconds"))

Salida:

2026-09-16T12:34:56.789+00:00

El valor microsecond de seis dígitos 789654 se convierte en .789. Python no redondea el valor a .790; timespec controla qué componentes aparecen, y los componentes de tiempo excluidos se truncan.

Usa un datetime consciente de zona horaria cuando la cadena deba identificar un instante real entre sistemas. Un valor ingenuo no tiene desplazamiento UTC, por lo que su texto formateado no puede distinguir por sí solo una hora local de UTC u otra zona.

isoformat() conserva el desplazamiento ya adjunto al objeto; no convierte el valor a UTC. Normaliza el datetime primero si tu contrato de datos exige UTC. En cambio, omite la conversión de zona horaria solo cuando el consumidor espera deliberadamente un valor local de reloj.

Usa strftime() para un diseño personalizado

Usa strftime() cuando necesites controlar el orden, los separadores u otros campos. La directiva %f produce seis dígitos de microsegundos. El corte con [:-3] elimina deliberadamente los tres últimos dígitos y deja precisión de milisegundos:

"""Show millisecond precision in a custom datetime string format."""

from datetime import datetime


value = datetime(2026, 9, 16, 12, 34, 56, 789654)
print(value.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3])

Salida:

2026-09-16 12:34:56.789

Este corte es seguro porque %f siempre proporciona un campo de seis dígitos rellenado con ceros, incluso cuando el valor original no tiene microsegundos. Mantén .%f al final del formato antes de usar [:-3]; de lo contrario, el corte podría eliminar caracteres de otro campo.

La operación trunca en lugar de redondear. Por ejemplo, 789999 microsegundos todavía se convierte en 789 milisegundos. Si una especificación exige redondeo, redondea el datetime antes de formatearlo y maneja un posible acarreo al siguiente segundo; cortar %f no puede implementar esa regla.

El estilo de importación determina cómo llamas a la clase. Con from datetime import datetime, llama a datetime.now(). Si en cambio escribes import datetime, llama a datetime.datetime.now().

Entiende str() y los límites del corte

str(value) simple equivale a value.isoformat(" "). Su timespec="auto" predeterminado omite el campo fraccionario cuando microsecond es cero y, de lo contrario, emite los seis dígitos de microsegundos. Por eso str(value) no garantiza un campo de milisegundos de tres dígitos, y aplicar [:-3] a ciegas es inseguro.

Este comportamiento de ancho variable es útil para visualización informal, pero no sirve para un campo de ancho fijo. Comprobar si hay un punto decimal antes de cortar evitaría corromper los segundos, pero duplicaría lógica que ya maneja isoformat(timespec="milliseconds") y exigiría más cuidado con los sufijos de zona horaria.

Este ejemplo de límite también muestra que la salida de milisegundos se trunca en 999999 microsegundos y que el valor singular "millisecond" no es válido:

"""Expose truncation, zero-microsecond slicing, and invalid-timespec boundaries."""

from datetime import datetime


almost_next_second = datetime(2026, 9, 16, 12, 34, 56, 999999)
without_fraction = datetime(2026, 9, 16, 12, 34, 56)

print(almost_next_second.isoformat(timespec="milliseconds"))
print(str(without_fraction))
print(str(without_fraction)[:-3])

try:
    without_fraction.isoformat(timespec="millisecond")
except ValueError as error:
    print(f"{type(error).__name__}: {error}")

Salida:

2026-09-16T12:34:56.999
2026-09-16 12:34:56
2026-09-16 12:34
ValueError: Unknown timespec value

La tercera línea no es una conversión válida a milisegundos: elimina :56 porque la entrada no tiene campo fraccionario. Prefiere isoformat(timespec="milliseconds") o usa un formato que contenga %f, en lugar de cortar el resultado de longitud variable de str().

Elige el método adecuado

Usa isoformat(timespec="milliseconds") para marcas de tiempo legibles por máquinas e intercambio estándar. Maneja microsegundos cero, truncamiento y desplazamientos de zona horaria sin manipulación manual de cadenas. Usa strftime() más [:-3] cuando un consumidor requiera un diseño personalizado.

Elige según el contrato de salida y no por comodidad: isoformat() proporciona una forma de fecha y hora estandarizada, strftime() proporciona una forma definida por quien llama, y str() proporciona un valor predeterminado amigable para humanos con precisión fraccionaria variable. En todos los casos, documenta si la falta de desplazamiento significa hora local, UTC por convención o zona horaria desconocida.

Estos métodos formatean un datetime existente; no lo convierten en milisegundos desde la época Unix ni analizan una cadena para convertirla en datetime. Recuerda también que tres dígitos mostrados describen precisión de milisegundos, no necesariamente la exactitud del reloj o del valor almacenado.