Menu

Formato de DateTime en C#: strings de formato estándar y personalizados, cultura, ISO 8601

Cómo dar formato a un DateTime como string en C#: los strings de formato estándar (d, D, o, s, u, t), patrones personalizados como yyyy-MM-dd HH:mm:ss, una tabla completa de especificadores, cómo cambia la salida con la cultura, ISO 8601 de ida y vuelta con "o", y los errores de mm frente a MM y hh frente a HH.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

DateTime.ToString(format) convierte una fecha en texto. El formato es o bien un string de formato estándar (una sola letra como d u o, cuyo patrón exacto viene de la cultura) o bien un patrón personalizado construido con especificadores como yyyy, MM y HH. Los mismos strings funcionan en la interpolación, $"{date:yyyy-MM-dd}", y en string.Format.

Salida:

2026-10-09
2026-10-09 18:30:07
09/10/2026
Oct 9, 2026
Friday, October 9
6:30 PM
18:30:07.045
Shipped 2026-10-09 at 18:30

Los ejemplos de esta página pasan CultureInfo.InvariantCulture para que la salida sea la misma en todas las máquinas; sin ella, ToString usa la cultura actual, que puede cambiar los nombres de los meses, los separadores e incluso el calendario.

Especificadores de formato personalizados

Un formato personalizado es un patrón en el que ciertas letras representan partes de la fecha. Distinguen mayúsculas y minúsculas: M es el mes y m el minuto, H es la hora de 24 horas y h la de 12 horas.

EspecificadorSignificadoEjemplo para 2026-10-09 18:30:07.045
yyyyAño, 4 dígitos2026
yyAño, 2 dígitos26
MMMMNombre completo del mesOctober
MMMNombre abreviado del mesOct
MMMes, 2 dígitos10
MMes, 1 o 2 dígitos10
ddddNombre completo del díaFriday
dddNombre abreviado del díaFri
ddDía del mes, 2 dígitos09
dDía del mes, 1 o 2 dígitos (dentro de un patrón)9
HHHora, de 00 a 2318
HHora, de 0 a 2318
hhHora, de 01 a 1206
hHora, de 1 a 126
mmMinuto, 2 dígitos30
ssSegundo, 2 dígitos07
fffMilisegundos045
fffffffTicks (siete dígitos fraccionarios)0450000
ttDesignador AM/PMPM
zzzDiferencia con UTC (DateTimeOffset u hora local)+02:00
KInformación de zona: Z, una diferencia o nadaZ (para un valor UTC)
/El separador de fecha de la cultura/ o . o -
:El separador de hora de la cultura:
'text' o \cTexto o carácter literal'at'

Cualquier otro carácter se copia tal cual. Eso incluye las letras que no son especificadores, y por eso "YYYY-DD" imprime tranquilamente YYYY-DD: en .NET no existen los especificadores Y ni D en mayúscula.

Una sola letra aislada se interpreta como un formato estándar, no como uno personalizado: ToString("d") es el patrón de fecha corta, no el número del día. Para obtener solo el día, escribe ToString("%d") o usa la propiedad Day.

Salida:

10/09/2026
9
20261009_183007
Week of Oct 9
18h30
2026-10-09T18:30:07
YYYY-DD

Strings de formato estándar

Los formatos estándar son letras sueltas cuyo patrón real lo define la cultura. Son la opción correcta para el texto que se muestra a los usuarios, porque cada cultura obtiene sus propias convenciones sin esfuerzo.

Salida:

d  10/09/2026
D  Friday, 09 October 2026
f  Friday, 09 October 2026 18:30
g  10/09/2026 18:30
G  10/09/2026 18:30:07
M  October 09
Y  2026 October
t  18:30
T  18:30:07
o  2026-10-09T18:30:07.0000000Z
s  2026-10-09T18:30:07
u  2026-10-09 18:30:07Z
r  Fri, 09 Oct 2026 18:30:07 GMT
en-US d: 10/9/2026, D: Friday, October 9, 2026
CódigoNombre¿Depende de la cultura?
d / DFecha corta / largaSí
t / THora corta / largaSí
f / FFecha larga con hora corta / largaSí
g / GFecha corta con hora corta / largaSí
MMes y díaSí
YAño y mesSí
oISO 8601 de ida y vuelta, 7 dígitos fraccionarios, zonaNo
sISO 8601 ordenable, sin fracciones ni zonaNo
uUniversal ordenable, termina en ZNo
rRFC 1123, para cabeceras HTTPNo

o, s, u y r producen el mismo texto en todas las culturas, lo que los hace seguros para logs, nombres de archivo e intercambio de datos. Ten en cuenta que en un DateTime, u y r no convierten el valor a UTC; lo imprimen tal cual y lo etiquetan como UTC, así que llama antes a ToUniversalTime() (o usa DateTime.UtcNow) si el valor es local. (En un DateTimeOffset sí convierten.)

La cultura cambia la salida

Los formatos estándar, los nombres de los meses y de los días, y los separadores / y : vienen todos de la cultura. Pasa una como segundo argumento de ToString:

Salida:

en-US  10/9/2026
en-GB  09/10/2026
de-DE  09.10.2026
fr-FR  09/10/2026
ja-JP  2026/10/09
Freitag, 9. Oktober 2026
vendredi 9 octobre 2026
09.10.2026
09/10/2026

Los datos de cultura no están congelados. .NET en Linux y macOS los lee de la biblioteca ICU instalada en el sistema, y desde .NET 5 también lo hace .NET en Windows 10 y posteriores (.NET Framework usa los datos NLS propios de Windows), así que un patrón puede cambiar ligeramente entre versiones y plataformas: las versiones recientes de ICU, por ejemplo, ponen un espacio estrecho de no separación en lugar de un espacio normal antes de "PM" en el formato de hora corta de Estados Unidos, y algunas dan las fechas cortas en español sin el cero inicial. Es un motivo más para no parsear nunca un texto al que se dio formato para mostrarlo.

De aquí salen dos reglas. Para el texto que lee una persona, da formato con su cultura (en un servidor, la de la petición, no la del servidor) y prefiere los formatos estándar, para que un lector alemán vea 09.10.2026 y uno estadounidense 10/9/2026. Para el texto que lee un programa, usa CultureInfo.InvariantCulture y un patrón sin ambigüedad como yyyy-MM-dd u o. Una fecha escrita con la cultura actual y parseada en otra máquina es una fuente clásica de días y meses intercambiados.

ISO 8601 y la ida y vuelta con "o"

El formato de ida y vuelta "o" escribe todos los ticks más la información de zona, así que parsear el texto devuelve exactamente el mismo DateTime, incluido su Kind:

Salida:

2026-10-09T18:30:07.0450000Z
2026-10-09T18:30:07.0450000
2026-10-09T20:30:07.0000000+02:00
True
Utc
2026-10-09T18:30:07Z
2026-10-09 20:30 +02:00

El sufijo Z marca UTC; un DateTime con Kind Unspecified no lleva sufijo; una hora local o un DateTimeOffset llevan su diferencia horaria (+02:00). Parsea con DateTimeStyles.RoundtripKind para que el Kind se conserve. Los serializadores de JSON, las bases de datos y el Date de JavaScript leen todos este formato.

Dar formato a un TimeSpan

TimeSpan tiene su propio conjunto, más pequeño, de especificadores personalizados: d (días), hh, mm, ss y fff. A diferencia de DateTime, todo carácter literal, incluidos : y ., debe escaparse con una barra invertida o ponerse entre comillas:

Salida:

1.03:25:09.1200000
1.03:25:09.1200000
03:25:09
1.03:25
25:09.120
27:25

hh en un formato de TimeSpan es el componente de horas (de 0 a 23), así que una duración de 27 horas se imprime como 03. Para totales de más de un día, calcula a partir de TotalHours como en la última línea. elapsed.ToString("hh:mm") sin la barra invertida lanza una FormatException.

Errores comunes

  • mm para el mes. "yyyy-mm-dd" imprime los minutos en medio: 2026-30-09. El mes es MM.
  • hh sin tt. "hh:mm" es un reloj de 12 horas sin AM ni PM, así que 06:30 es ambiguo. Usa HH para la hora de 24 horas.
  • YYYY y DD. No son especificadores en .NET; se imprimen literalmente. Usa yyyy y dd.
  • / en un patrón para datos. Es el separador de fecha de la cultura. Ponlo entre comillas o usa la cultura invariante.
  • ToString() por defecto en logs o archivos. El formato depende de la máquina. Pasa un formato y una cultura.
  • Hora local etiquetada como UTC. "u", "r" y una 'Z' escrita a mano no convierten; convierte antes.
  • Parsear con un patrón distinto del que usaste para escribir. Guarda los strings de formato de los datos en una constante y úsala tanto con ToString como con ParseExact.

Preguntas frecuentes

¿Cómo doy formato a un DateTime como yyyy-MM-dd en C#?

date.ToString("yyyy-MM-dd") da 2026-10-09. En un string interpolado escribe $"{date:yyyy-MM-dd}". Añade " HH:mm:ss" para la hora en formato de 24 horas. Pasa CultureInfo.InvariantCulture como segundo argumento cuando el texto sea para un archivo o para otro programa, así el calendario, los nombres de los meses y los separadores nunca dependen de la máquina.

¿Qué diferencia hay entre mm y MM en los formatos de fecha de C#?

MM es el mes (de 01 a 12) y mm es el minuto (de 00 a 59). El formato distingue mayúsculas y minúsculas, así que yyyy-mm-dd imprime los minutos donde debería ir el mes, un bug fácil de pasar por alto si miras un solo valor. Del mismo modo, HH es la hora en formato de 24 horas y hh la hora en formato de 12 horas.

¿Cómo doy formato a un DateTime en ISO 8601 en C#?

Usa el formato de ida y vuelta "o": DateTime.UtcNow.ToString("o") da 2026-10-09T18:30:07.0450000Z, con siete dígitos fraccionarios y una Z para UTC o una diferencia horaria para las horas locales. "s" da la forma ordenable más corta, sin fracciones ni zona, y "yyyy-MM-ddTHH:mm:ssZ" es una variante personalizada habitual.

¿Cómo muestro AM y PM en un formato de fecha de C#?

Usa hh o h para el reloj de 12 horas y tt para el designador AM/PM: date.ToString("h:mm tt", CultureInfo.GetCultureInfo("en-US")) da 6:30 PM. El designador viene de la cultura, y algunas culturas no tienen ninguno, así que pasa una cultura de forma explícita cuando necesites AM y PM.

¿Por qué mi formato de fecha muestra puntos en lugar de barras?

En un string de formato, / no es una barra literal sino el separador de fecha de la cultura, y : es el separador de hora de la cultura. En una máquina en alemán, dd/MM/yyyy imprime 09.10.2026. Pon el carácter entre comillas para forzarlo, dd'/'MM'/'yyyy, o da formato con CultureInfo.InvariantCulture.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR