Compartir a través de


Estructura System.DateTime

En este artículo se proporcionan comentarios adicionales a la documentación de referencia de esta API.

Importante

Las eras en los calendarios japoneses se basan en el reinado del emperador y, por tanto, se espera que cambien. Por ejemplo, el 1 de mayo de 2019 marcó el principio de la era Reiwa en JapaneseCalendar y JapaneseLunisolarCalendar. Este cambio de era afecta a todas las aplicaciones que usan estos calendarios. Para obtener más información y determinar si las aplicaciones se ven afectadas, consulte Control de una nueva era en el calendario japonés en .NET. Para obtener información sobre cómo probar las aplicaciones en sistemas Windows para garantizar su preparación para el cambio de era, consulte Preparación de la aplicación para el cambio de la era japonesa. Para ver las características de .NET que admiten calendarios con varias eras y procedimientos recomendados al trabajar con calendarios que admiten varias eras, consulte Trabajar con eras.

Información general

El DateTime tipo de valor representa fechas y horas con valores que van desde 00:00:00 (medianoche), 1 de enero de 0001 Anno Domini (Era común) hasta 11:59:59 P.M., 31 de diciembre de 9999 A.D. (C.E.) en el calendario gregoriano.

Los valores de tiempo se miden en unidades de 100 nanosegundos denominadas tics. Una fecha concreta es el número de ticks desde las 12:00 de la medianoche del 1 de enero de 0001 A.D. (C.E.) en el calendario GregorianCalendar. El número excluye los ticks que se sumarían por segundos bisiestos. Por ejemplo, un valor de ticks de 31241376000000000L representa la fecha viernes, 01 de enero de 0100 12:00:00 medianoche. Un DateTime valor siempre se expresa en el contexto de un calendario explícito o predeterminado.

Nota:

Si está trabajando con un valor de ticks que desea convertir a algún otro intervalo de tiempo, como minutos o segundos, debe utilizar la constante TimeSpan.TicksPerDay, TimeSpan.TicksPerHour, TimeSpan.TicksPerMinute, TimeSpan.TicksPerSecond o TimeSpan.TicksPerMillisecond para realizar la conversión. Por ejemplo, para sumar el número de segundos representados por un número especificado de ticks al componente Second de un valor DateTime, puede usar la expresión dateValue.Second + nTicks/Timespan.TicksPerSecond.

Puede ver el origen de todo el conjunto de ejemplos de este artículo en Visual Basic, F#o C#.

Nota:

Una alternativa a la DateTime estructura para trabajar con valores de fecha y hora en determinadas zonas horarias es la DateTimeOffset estructura. La DateTimeOffset estructura almacena información de fecha y hora en un campo privado DateTime, así como el número de minutos por los que esa fecha y hora difieren de UTC en un campo privado Int16. Esto permite que un DateTimeOffset valor refleje la hora en una zona horaria determinada, mientras que un DateTime valor solo puede reflejar utc y la hora de la zona horaria local. Para obtener información sobre cuándo usar la DateTime estructura o la DateTimeOffset estructura al trabajar con valores de fecha y hora, vea Elegir entre DateTime, DateTimeOffset, TimeSpan y TimeZoneInfo.

Nota:

Algunos ejemplos de C# de este artículo se ejecutan en el Try.NET ejecutor de código en línea y entorno de pruebas. Haga clic en el botón Ejecutar para ejecutar un ejemplo en una ventana interactiva. Una vez que se ejecuta el código, puede modificar y ejecutar el código modificado si vuelve a hacer clic en Ejecutar. El código modificado se ejecuta en la ventana interactiva o, si se produce un error en la compilación, en la ventana interactiva se muestran todos los mensajes de error del compilador de C#.

La zona horaria local del ejecutor de código en línea de Try.NET y del área de juegos es la hora universal coordinada o UTC. Esto puede afectar al comportamiento y la salida de ejemplos que ilustran los tipos DateTime, DateTimeOffset y TimeZoneInfo y sus miembros.

En este artículo se incluyen varios ejemplos que usan el DateTime tipo :

Ejemplos de inicialización

Dar formato DateTime a objetos como ejemplos de cadenas

Analizar cadenas como ejemplos de objetos DateTime

DateTime Ejemplos de resolución

Ejemplos de cultura y calendarios

Ejemplos de persistencia

Inicialización de un objeto DateTime

Puede asignar un valor inicial a un nuevo DateTime valor de muchas maneras diferentes:

  • Llamar a un constructor, ya sea uno en el que especifique argumentos para los valores o use el constructor sin parámetros implícito.
  • Asignar un DateTime al valor de retorno de una propiedad o método.
  • Análisis sintáctico de un valor DateTime a partir de su representación de cadena.
  • Uso de características de lenguaje específicas de Visual Basic para instanciar un DateTime.

Los fragmentos de código siguientes muestran ejemplos de cada uno.

Invocar compiladores

Se llama a cualquiera de las sobrecargas del compilador DateTime que especifican elementos del valor de fecha y hora (como el año, mes y día, o el número de ticks). El código siguiente crea una fecha específica mediante el DateTime constructor que especifica el año, mes, día, hora, minuto y segundo.

Dim date1 As New Date(2008, 5, 1, 8, 30, 52)
var date1 = new DateTime(2008, 5, 1, 8, 30, 52);
Console.WriteLine(date1);
let date1 = DateTime(2008, 5, 1, 8, 30, 52)
printfn $"{date1}"

Se invoca el constructor implícito sin parámetros de la estructura DateTime cuando se desea que se inicialice DateTime a su valor predeterminado. (Para obtener más información sobre el constructor implícito sin parámetros de un tipo de valor, vea Tipos de valor). Algunos compiladores también admiten declarar un DateTime valor sin asignar explícitamente un valor. La creación de un valor sin una inicialización explícita también da como resultado el valor predeterminado. En el ejemplo siguiente se muestra el DateTime constructor sin parámetros implícito en C# y Visual Basic, así como una DateTime declaración sin asignación en Visual Basic.

Dim dat1 As DateTime
' The following method call displays 1/1/0001 12:00:00 AM.
Console.WriteLine(dat1.ToString(System.Globalization.CultureInfo.InvariantCulture))
' The following method call displays True.
Console.WriteLine(dat1.Equals(Date.MinValue))

Dim dat2 As New DateTime()
' The following method call displays 1/1/0001 12:00:00 AM.
Console.WriteLine(dat2.ToString(System.Globalization.CultureInfo.InvariantCulture))
' The following method call displays True.
Console.WriteLine(dat2.Equals(Date.MinValue))
var dat1 = new DateTime();
// The following method call displays 1/1/0001 12:00:00 AM.
Console.WriteLine(dat1.ToString(System.Globalization.CultureInfo.InvariantCulture));
// The following method call displays True.
Console.WriteLine(dat1.Equals(DateTime.MinValue));
let dat1 = DateTime()

// The following method call displays 1/1/0001 12:00:00 AM.
printfn $"{dat1.ToString System.Globalization.CultureInfo.InvariantCulture}"

// The following method call displays True.
printfn $"{dat1.Equals DateTime.MinValue}"

Asignación de un valor calculado

Puede asignar al DateTime objeto un valor de fecha y hora devuelto por una propiedad o método. En el ejemplo siguiente se asignan la fecha y hora actuales, la fecha y hora universal coordinadas (UTC) actuales y la fecha actual a tres variables nuevas DateTime .

Dim date1 As Date = Date.Now
Dim date2 As Date = Date.UtcNow
Dim date3 As Date = Date.Today
DateTime date1 = DateTime.Now;
DateTime date2 = DateTime.UtcNow;
DateTime date3 = DateTime.Today;
let date1 = DateTime.Now
let date2 = DateTime.UtcNow
let date3 = DateTime.Today

Análisis de una cadena que representa un valor DateTime

Los métodos Parse, ParseExact, TryParse y TryParseExact convierten una cadena en su valor equivalente de fecha y hora. En los ejemplos siguientes se usan los Parse métodos y ParseExact para analizar una cadena y convertirlo en un DateTime valor. El segundo formato usa un formulario compatible con el estándar ISO 8601 para representar una fecha y hora en formato de cadena. Esta representación estándar se usa a menudo para transferir información de fecha en servicios web.

Dim dateString As String = "5/1/2008 8:30:52 AM"
Dim date1 As Date = Date.Parse(dateString,
                       System.Globalization.CultureInfo.InvariantCulture)
Dim iso8601String As String = "20080501T08:30:52Z"
Dim dateISO8602 As Date = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ",
                              System.Globalization.CultureInfo.InvariantCulture)
Console.WriteLine(dateISO8602)
var dateString = "5/1/2008 8:30:52 AM";
DateTime date1 = DateTime.Parse(dateString,
                          System.Globalization.CultureInfo.InvariantCulture);
var iso8601String = "20080501T08:30:52Z";
DateTime dateISO8602 = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ",
                                System.Globalization.CultureInfo.InvariantCulture);
let dateString = "5/1/2008 8:30:52 AM"
let date1 = DateTime.Parse(dateString, System.Globalization.CultureInfo.InvariantCulture)
let iso8601String = "20080501T08:30:52Z"
let dateISO8602 = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ", System.Globalization.CultureInfo.InvariantCulture)

Los TryParse métodos y TryParseExact indican si una cadena es una representación válida de un DateTime valor y, si es así, realiza la conversión.

Sintaxis específica del lenguaje para Visual Basic

La siguiente instrucción de Visual Basic inicializa un nuevo DateTime valor.

Dim date1 As Date = #5/1/2008 8:30:52AM#

Valores DateTime y sus representaciones de cadena

Internamente, todos los valores DateTime se representan como el número de ticks (el número de intervalos de 100 nanosegundos) que han transcurrido desde las 12:00:00 de la medianoche del 1 de enero de 0001. El valor real DateTime es independiente de la forma en que ese valor aparece cuando se muestra. La apariencia de un DateTime valor es el resultado de una operación de formato que convierte un valor en su representación de cadena.

La apariencia de los valores de fecha y hora depende de la cultura, los estándares internacionales, los requisitos de aplicación y las preferencias personales. La estructura DateTime ofrece flexibilidad en el formateo de valores de fecha y hora mediante sobrecargas de ToString. El método predeterminado DateTime.ToString() devuelve la representación en cadena de un valor de fecha y hora utilizando el patrón de fecha corta y tiempo largo de la referencia cultural actual. En el ejemplo siguiente se usa el método predeterminado DateTime.ToString() . Muestra la fecha y hora con el patrón de fecha y hora breves para la referencia cultural actual. La cultura estadounidense es la cultura actual del ordenador en el que se ejecutó el ejemplo.

var date1 = new DateTime(2008, 3, 1, 7, 0, 0);
Console.WriteLine(date1.ToString());
// For en-US culture, displays 3/1/2008 7:00:00 AM
let date1 = DateTime(2008, 3, 1, 7, 0, 0)
printfn $"{date1.ToString()}"
// For en-US culture, displays 3/1/2008 7:00:00 AM
Dim date1 As Date = #3/1/2008 7:00AM#
Console.WriteLine(date1.ToString())
' For en-US culture, displays 3/1/2008 7:00:00 AM

Es posible que tenga que formatear fechas en una cultura específica para admitir escenarios web en los que el servidor puede estar en una cultura diferente del cliente. Especifique la cultura utilizando el método DateTime.ToString(IFormatProvider) para crear la representación de fecha corta y hora larga en una cultura específica. En el ejemplo siguiente se usa el método DateTime.ToString(IFormatProvider) para mostrar la fecha y la hora mediante el patrón de fecha corta y tiempo largo para la cultura fr-FR.

var date1 = new DateTime(2008, 3, 1, 7, 0, 0);
Console.WriteLine(date1.ToString(System.Globalization.CultureInfo.CreateSpecificCulture("fr-FR")));
// Displays 01/03/2008 07:00:00
let date1 = DateTime(2008, 3, 1, 7, 0, 0)
printfn $"""{date1.ToString(System.Globalization.CultureInfo.CreateSpecificCulture "fr-FR")}"""
// Displays 01/03/2008 07:00:00
Dim date1 As Date = #3/1/2008 7:00AM#
Console.WriteLine(date1.ToString(System.Globalization.CultureInfo.CreateSpecificCulture("fr-FR")))
' Displays 01/03/2008 07:00:00

Otras aplicaciones pueden requerir representaciones de cadena diferentes de una fecha. El DateTime.ToString(String) método devuelve la representación de cadena definida por un especificador de formato estándar o personalizado utilizando las convenciones de formato de la cultura actual. En el ejemplo siguiente se usa el DateTime.ToString(String) método para mostrar el patrón de fecha y hora completo para la configuración cultural en-US, que es la configuración cultural actual en el equipo donde se ejecutó el ejemplo.

var date1 = new DateTime(2008, 3, 1, 7, 0, 0);
Console.WriteLine(date1.ToString("F"));
// Displays Saturday, March 01, 2008 7:00:00 AM
let date1 = DateTime(2008, 3, 1, 7, 0, 0)
printfn $"""{date1.ToString "F"}"""
// Displays Saturday, March 01, 2008 7:00:00 AM
Dim date1 As Date = #3/1/2008 7:00AM#
Console.WriteLine(date1.ToString("F"))
' Displays Saturday, March 01, 2008 7:00:00 AM

Por último, puede especificar la referencia cultural y el formato mediante el DateTime.ToString(String, IFormatProvider) método . En el ejemplo siguiente se usa el método DateTime.ToString(String, IFormatProvider) para mostrar el patrón completo de fecha y hora para la cultura fr-FR.

var date1 = new DateTime(2008, 3, 1, 7, 0, 0);
Console.WriteLine(date1.ToString("F", new System.Globalization.CultureInfo("fr-FR")));
// Displays samedi 1 mars 2008 07:00:00
let date1 = DateTime(2008, 3, 1, 7, 0, 0)
printfn $"""{date1.ToString("F", new System.Globalization.CultureInfo "fr-FR")}"""
// Displays samedi 1 mars 2008 07:00:00
Dim date1 As Date = #3/1/2008 7:00AM#
Console.WriteLine(date1.ToString("F", New System.Globalization.CultureInfo("fr-FR")))
' Displays samedi 1 mars 2008 07:00:00

La sobrecarga DateTime.ToString(String) también se puede usar con una cadena de formato personalizada para especificar otros formatos. En el ejemplo siguiente se muestra cómo dar formato a una cadena mediante el formato estándar ISO 8601 que a menudo se usa para los servicios web. El formato Iso 8601 no tiene una cadena de formato estándar correspondiente.

var date1 = new DateTime(2008, 3, 1, 7, 0, 0, DateTimeKind.Utc);
Console.WriteLine(date1.ToString("yyyy-MM-ddTHH:mm:sszzz", System.Globalization.CultureInfo.InvariantCulture));
// Displays 2008-03-01T07:00:00+00:00
let date1 = DateTime(2008, 3, 1, 7, 0, 0, DateTimeKind.Utc)
printfn $"""{date1.ToString("yyyy-MM-ddTHH:mm:sszzz", System.Globalization.CultureInfo.InvariantCulture)}"""
// Displays 2008-03-01T07:00:00+00:00
Dim date1 As DateTime = New DateTime(2008, 3, 1, 7, 0, 0, DateTimeKind.Utc)
Console.WriteLine(date1.ToString("yyyy-MM-ddTHH:mm:sszzz", System.Globalization.CultureInfo.InvariantCulture))
' Displays 2008-03-01T07:00:00+00:00

Para obtener más información sobre los valores de formato DateTime , vea Cadenas de formato de fecha y hora estándar y cadenas de formato de fecha y hora personalizados.

Análisis sintáctico de valores DateTime a partir de cadenas

El análisis convierte una cadena que representa una fecha y una hora en un valor DateTime. Normalmente, las cadenas de fecha y hora tienen dos usos diferentes en las aplicaciones:

  • Una fecha y hora toma una variedad de formas y refleja las convenciones de la cultura actual o de una cultura específica. Por ejemplo, una aplicación permite que un usuario cuya referencia cultural actual esté en-US escriba un valor de fecha como "12/15/2013" o "15 de diciembre de 2013". Permite que un usuario cuya referencia cultural actual esté en-gb escriba un valor de fecha como "15/12/2013" o "15 de diciembre de 2013".

  • Una fecha y hora se representa en un formato predefinido. Por ejemplo, una aplicación serializa una fecha como "20130103" independientemente de la referencia cultural en la que se ejecuta la aplicación. Una aplicación puede requerir que las fechas se escriban en el formato de fecha corta de la cultura actual.

Utilizas el método Parse o TryParse para convertir una cadena de uno de los formatos comunes de fecha y hora utilizados por una cultura a un valor DateTime. En el ejemplo siguiente se muestra cómo se puede usar TryParse para convertir cadenas de fecha en diferentes formatos específicos de la cultura a un valor DateTime. Cambia la referencia cultural actual a inglés (Reino Unido) y llama al método GetDateTimeFormats() para generar una matriz de cadenas de fecha y hora. A continuación, pasa cada elemento de la matriz al TryParse método . La salida del ejemplo muestra que el método de análisis pudo convertir correctamente cada una de las cadenas de fecha y hora específicas de la referencia cultural.

System.Threading.Thread.CurrentThread.CurrentCulture =
    System.Globalization.CultureInfo.CreateSpecificCulture("en-GB");

var date1 = new DateTime(2013, 6, 1, 12, 32, 30);
var badFormats = new List<String>();

Console.WriteLine($"{"Date String",-37} {"Date",-19}\n");
foreach (var dateString in date1.GetDateTimeFormats())
{
    DateTime parsedDate;
    if (DateTime.TryParse(dateString, out parsedDate))
        Console.WriteLine($"{dateString,-37} {DateTime.Parse(dateString),-19}");
    else
        badFormats.Add(dateString);
}

// Display strings that could not be parsed.
if (badFormats.Count > 0)
{
    Console.WriteLine("\nStrings that could not be parsed: ");
    foreach (var badFormat in badFormats)
        Console.WriteLine($"   {badFormat}");
}
// Press "Run" to see the output.
System.Threading.Thread.CurrentThread.CurrentCulture <-
    System.Globalization.CultureInfo.CreateSpecificCulture "en-GB"

let date1 = DateTime(2013, 6, 1, 12, 32, 30)
let badFormats = ResizeArray<String>()

printfn "%-37s %-19s\n" "Date String" "Date"
for dateString in date1.GetDateTimeFormats() do
    match DateTime.TryParse dateString with
    | true, parsedDate ->
        printfn $"%-37s{dateString} %-19O{parsedDate}\n" 
    | _ ->
        badFormats.Add dateString

// Display strings that could not be parsed.
if badFormats.Count > 0 then
    printfn "\nStrings that could not be parsed: "
    for badFormat in badFormats do
        printfn $"   {badFormat}"
// Press "Run" to see the output.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB")

Dim date1 As New DateTime(2013, 6, 1, 12, 32, 30)
Dim badFormats As New List(Of String)

Console.WriteLine($"{"Date String",-37} {"Date",-19}")
Console.WriteLine()
For Each dateString As String In date1.GetDateTimeFormats()
    Dim parsedDate As DateTime
    If DateTime.TryParse(dateString, parsedDate) Then
        Console.WriteLine($"{dateString,-37} {DateTime.Parse(dateString),-19:g}")
    Else
        badFormats.Add(dateString)
    End If
Next

' Display strings that could not be parsed.
If badFormats.Count > 0 Then
    Console.WriteLine()
    Console.WriteLine("Strings that could not be parsed: ")
    For Each badFormat In badFormats
        Console.WriteLine($"   {badFormat}")
    Next
End If
' The example displays the following output:
'       Date String                           Date               
'       
'       01/06/2013                            01/06/2013 00:00:00
'       01/06/13                              01/06/2013 00:00:00
'       1/6/13                                01/06/2013 00:00:00
'       1.6.13                                01/06/2013 00:00:00
'       2013-06-01                            01/06/2013 00:00:00
'       01 June 2013                          01/06/2013 00:00:00
'       1 June 2013                           01/06/2013 00:00:00
'       01 June 2013 12:32                    01/06/2013 12:32:00
'       01 June 2013 12:32                    01/06/2013 12:32:00
'       01 June 2013 12:32 PM                 01/06/2013 12:32:00
'       01 June 2013 12:32 PM                 01/06/2013 12:32:00
'       1 June 2013 12:32                     01/06/2013 12:32:00
'       1 June 2013 12:32                     01/06/2013 12:32:00
'       1 June 2013 12:32 PM                  01/06/2013 12:32:00
'       1 June 2013 12:32 PM                  01/06/2013 12:32:00
'       01 June 2013 12:32:30                 01/06/2013 12:32:30
'       01 June 2013 12:32:30                 01/06/2013 12:32:30
'       01 June 2013 12:32:30 PM              01/06/2013 12:32:30
'       01 June 2013 12:32:30 PM              01/06/2013 12:32:30
'       1 June 2013 12:32:30                  01/06/2013 12:32:30
'       1 June 2013 12:32:30                  01/06/2013 12:32:30
'       1 June 2013 12:32:30 PM               01/06/2013 12:32:30
'       1 June 2013 12:32:30 PM               01/06/2013 12:32:30
'       01/06/2013 12:32                      01/06/2013 12:32:00
'       01/06/2013 12:32                      01/06/2013 12:32:00
'       01/06/2013 12:32 PM                   01/06/2013 12:32:00
'       01/06/2013 12:32 PM                   01/06/2013 12:32:00
'       01/06/13 12:32                        01/06/2013 12:32:00
'       01/06/13 12:32                        01/06/2013 12:32:00
'       01/06/13 12:32 PM                     01/06/2013 12:32:00
'       01/06/13 12:32 PM                     01/06/2013 12:32:00
'       1/6/13 12:32                          01/06/2013 12:32:00
'       1/6/13 12:32                          01/06/2013 12:32:00
'       1/6/13 12:32 PM                       01/06/2013 12:32:00
'       1/6/13 12:32 PM                       01/06/2013 12:32:00
'       1.6.13 12:32                          01/06/2013 12:32:00
'       1.6.13 12:32                          01/06/2013 12:32:00
'       1.6.13 12:32 PM                       01/06/2013 12:32:00
'       1.6.13 12:32 PM                       01/06/2013 12:32:00
'       2013-06-01 12:32                      01/06/2013 12:32:00
'       2013-06-01 12:32                      01/06/2013 12:32:00
'       2013-06-01 12:32 PM                   01/06/2013 12:32:00
'       2013-06-01 12:32 PM                   01/06/2013 12:32:00
'       01/06/2013 12:32:30                   01/06/2013 12:32:30
'       01/06/2013 12:32:30                   01/06/2013 12:32:30
'       01/06/2013 12:32:30 PM                01/06/2013 12:32:30
'       01/06/2013 12:32:30 PM                01/06/2013 12:32:30
'       01/06/13 12:32:30                     01/06/2013 12:32:30
'       01/06/13 12:32:30                     01/06/2013 12:32:30
'       01/06/13 12:32:30 PM                  01/06/2013 12:32:30
'       01/06/13 12:32:30 PM                  01/06/2013 12:32:30
'       1/6/13 12:32:30                       01/06/2013 12:32:30
'       1/6/13 12:32:30                       01/06/2013 12:32:30
'       1/6/13 12:32:30 PM                    01/06/2013 12:32:30
'       1/6/13 12:32:30 PM                    01/06/2013 12:32:30
'       1.6.13 12:32:30                       01/06/2013 12:32:30
'       1.6.13 12:32:30                       01/06/2013 12:32:30
'       1.6.13 12:32:30 PM                    01/06/2013 12:32:30
'       1.6.13 12:32:30 PM                    01/06/2013 12:32:30
'       2013-06-01 12:32:30                   01/06/2013 12:32:30
'       2013-06-01 12:32:30                   01/06/2013 12:32:30
'       2013-06-01 12:32:30 PM                01/06/2013 12:32:30
'       2013-06-01 12:32:30 PM                01/06/2013 12:32:30
'       01 June                               01/06/2013 00:00:00
'       01 June                               01/06/2013 00:00:00
'       2013-06-01T12:32:30.0000000           01/06/2013 12:32:30
'       2013-06-01T12:32:30.0000000           01/06/2013 12:32:30
'       Sat, 01 Jun 2013 12:32:30 GMT         01/06/2013 05:32:30
'       Sat, 01 Jun 2013 12:32:30 GMT         01/06/2013 05:32:30
'       2013-06-01T12:32:30                   01/06/2013 12:32:30
'       12:32                                 22/04/2013 12:32:00
'       12:32                                 22/04/2013 12:32:00
'       12:32 PM                              22/04/2013 12:32:00
'       12:32 PM                              22/04/2013 12:32:00
'       12:32:30                              22/04/2013 12:32:30
'       12:32:30                              22/04/2013 12:32:30
'       12:32:30 PM                           22/04/2013 12:32:30
'       12:32:30 PM                           22/04/2013 12:32:30
'       2013-06-01 12:32:30Z                  01/06/2013 05:32:30
'       01 June 2013 19:32:30                 01/06/2013 19:32:30
'       01 June 2013 19:32:30                 01/06/2013 19:32:30
'       01 June 2013 07:32:30 PM              01/06/2013 19:32:30
'       01 June 2013 7:32:30 PM               01/06/2013 19:32:30
'       1 June 2013 19:32:30                  01/06/2013 19:32:30
'       1 June 2013 19:32:30                  01/06/2013 19:32:30
'       1 June 2013 07:32:30 PM               01/06/2013 19:32:30
'       1 June 2013 7:32:30 PM                01/06/2013 19:32:30
'       June 2013                             01/06/2013 00:00:00
'       June 2013                             01/06/2013 00:00:00

Utiliza los métodos ParseExact y TryParseExact para convertir una cadena en un valor DateTime que debe coincidir con un formato o formatos concretos. Especifique una o varias cadenas de formato de fecha y hora como parámetro para el método de análisis. En el ejemplo siguiente se usa el TryParseExact(String, String[], IFormatProvider, DateTimeStyles, DateTime) método para convertir cadenas que deben tener un formato "aaaaMMdd" o un formato "HHmmss" en DateTime valores.

string[] formats = { "yyyyMMdd", "HHmmss" };
string[] dateStrings = { "20130816", "20131608", "  20130816   ",
                   "115216", "521116", "  115216  " };
DateTime parsedDate;

foreach (var dateString in dateStrings)
{
    if (DateTime.TryParseExact(dateString, formats, null,
                               System.Globalization.DateTimeStyles.AllowWhiteSpaces |
                               System.Globalization.DateTimeStyles.AdjustToUniversal,
                               out parsedDate))
        Console.WriteLine($"{dateString} --> {parsedDate:g}");
    else
        Console.WriteLine($"Cannot convert {dateString}");
}
// The example displays the following output:
//       20130816 --> 8/16/2013 12:00 AM
//       Cannot convert 20131608
//         20130816    --> 8/16/2013 12:00 AM
//       115216 --> 4/22/2013 11:52 AM
//       Cannot convert 521116
//         115216   --> 4/22/2013 11:52 AM
let formats = [| "yyyyMMdd"; "HHmmss" |]
let dateStrings = 
    [ "20130816"; "20131608"; "  20130816   "
      "115216"; "521116"; "  115216  " ]

for dateString in dateStrings do
    match DateTime.TryParseExact(dateString, formats, null,
                                System.Globalization.DateTimeStyles.AllowWhiteSpaces |||
                                System.Globalization.DateTimeStyles.AdjustToUniversal) with
    | true, parsedDate ->
        printfn $"{dateString} --> {parsedDate:g}"
    | _ ->
        printfn $"Cannot convert {dateString}"

// The example displays the following output:
//       20130816 --> 8/16/2013 12:00 AM
//       Cannot convert 20131608
//         20130816    --> 8/16/2013 12:00 AM
//       115216 --> 4/22/2013 11:52 AM
//       Cannot convert 521116
//         115216   --> 4/22/2013 11:52 AM
Dim formats() As String = {"yyyyMMdd", "HHmmss"}
Dim dateStrings() As String = {"20130816", "20131608",
                              "  20130816   ", "115216",
                              "521116", "  115216  "}
Dim parsedDate As DateTime

For Each dateString As String In dateStrings
    If DateTime.TryParseExact(dateString, formats, Nothing,
                           DateTimeStyles.AllowWhiteSpaces Or
                           DateTimeStyles.AdjustToUniversal,
                           parsedDate) Then
        Console.WriteLine($"{dateString} --> {parsedDate:g}")
    Else
        Console.WriteLine($"Cannot convert {dateString}")
    End If
Next
' The example displays the following output:
'       20130816 --> 8/16/2013 12:00 AM
'       Cannot convert 20131608
'         20130816    --> 8/16/2013 12:00 AM
'       115216 --> 4/22/2013 11:52 AM
'       Cannot convert 521116
'         115216   --> 4/22/2013 11:52 AM

Un uso común para ParseExact es convertir una representación de cadena de un servicio web, normalmente en formato estándar ISO 8601 . En el código siguiente se muestra la cadena de formato correcta que se va a usar:

var iso8601String = "20080501T08:30:52Z";
DateTime dateISO8602 = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ",
    System.Globalization.CultureInfo.InvariantCulture);
Console.WriteLine($"{iso8601String} --> {dateISO8602:g}");
let iso8601String = "20080501T08:30:52Z"
let dateISO8602 = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ", System.Globalization.CultureInfo.InvariantCulture)

printfn $"{iso8601String} --> {dateISO8602:g}"
Dim iso8601String As String = "20080501T08:30:52Z"
Dim dateISO8602 As DateTime = DateTime.ParseExact(iso8601String, "yyyyMMddTHH:mm:ssZ", CultureInfo.InvariantCulture)
Console.WriteLine($"{iso8601String} --> {dateISO8602:g}")

Si no se puede analizar una cadena, los Parse métodos y ParseExact producen una excepción. Los TryParse métodos y TryParseExact devuelven un Boolean valor que indica si la conversión se realizó correctamente o no. Debe usar los TryParse métodos o TryParseExact en escenarios en los que el rendimiento es importante. La operación de análisis de cadenas de fecha y hora tiende a tener una alta tasa de errores y el control de excepciones es costoso. Use estos métodos si los usuarios escriben cadenas o proceden de un origen desconocido.

Para obtener más información sobre el análisis de valores de fecha y hora, vea Analizar cadenas de fecha y hora.

Valores dateTime

Las descripciones de los valores de hora del DateTime tipo se expresan a menudo mediante el estándar hora universal coordinada (UTC). Hora universal coordinada es el nombre reconocido internacionalmente por la hora media de Greenwich (GMT). La hora universal coordinada es la hora medida en longitud de cero grados, el punto de origen UTC. El horario de verano no es aplicable al tiempo universal coordinado (UTC).

La hora local es relativa a una zona horaria determinada. Una zona horaria está asociada a un desplazamiento de zona horaria. Un desplazamiento de zona horaria es el desplazamiento de la zona horaria medida en horas desde el punto de origen UTC. Además, la hora local se ve afectada opcionalmente por el horario de verano, lo que agrega o resta un ajuste de intervalo de tiempo. La hora local se calcula agregando el desplazamiento de zona horaria a UTC y ajustando el horario de verano si es necesario. El desplazamiento de zona horaria en el punto de origen UTC es cero.

La hora UTC es adecuada para cálculos, comparaciones y almacenar fechas y hora en archivos. La hora local es adecuada para mostrarse en interfaces de usuario de aplicaciones de escritorio. Las aplicaciones compatibles con zona horaria (como muchas aplicaciones web) también necesitan trabajar con una serie de otras zonas horarias.

Si la Kind propiedad de un DateTime objeto es DateTimeKind.Unspecified, no se especifica si la hora representada es la hora local, la hora UTC o una hora en alguna otra zona horaria.

Resolución de fecha y hora

Nota:

Como alternativa a realizar la aritmética de fecha y hora en DateTime valores para medir el tiempo transcurrido, puede usar la Stopwatch clase .

La Ticks propiedad expresa los valores de fecha y hora en unidades de un diez millones de segundos. La propiedad Millisecond devuelve las milésimas de segundo de un valor de fecha y hora. El uso de llamadas repetidas a la DateTime.Now propiedad para medir el tiempo transcurrido depende del reloj del sistema. El reloj del sistema en los sistemas Windows 7 y Windows 8 tiene una resolución de aproximadamente 15 milisegundos. Esta resolución afecta a intervalos de tiempo pequeños inferiores a 100 milisegundos.

En el ejemplo siguiente se muestra la dependencia de los valores actuales de fecha y hora en la resolución del reloj del sistema. En el ejemplo, un bucle externo se repite 20 veces y un bucle interno sirve para retrasar el bucle externo. Si el valor del contador de bucle externo es 10, una llamada al Thread.Sleep método introduce un retraso de cinco milisegundos. En el ejemplo siguiente se muestra el número de milisegundos devueltos por la DateTime.Now.Milliseconds propiedad cambia solo después de la llamada a Thread.Sleep.

string output = "";
for (int ctr = 0; ctr <= 20; ctr++)
{
    output += String.Format($"{DateTime.Now.Millisecond}\n");
    // Introduce a delay loop.
    for (int delay = 0; delay <= 1000; delay++)
    { }

    if (ctr == 10)
    {
        output += "Thread.Sleep called...\n";
        System.Threading.Thread.Sleep(5);
    }
}
Console.WriteLine(output);
// Press "Run" to see the output.
let mutable output = ""
for i = 0 to 20 do
    output <- output + $"{DateTime.Now.Millisecond}\n"
    // Introduce a delay loop.
    for _ = 0 to 1000 do ()

    if i = 10 then
        output <- output + "Thread.Sleep called...\n"
        System.Threading.Thread.Sleep 5

printfn $"{output}"
// Press "Run" to see the output.
Dim output As String = ""
For ctr As Integer = 0 To 20
    output += Date.Now.Millisecond.ToString() + vbCrLf
    ' Introduce a delay loop.
    For delay As Integer = 0 To 1000
    Next

    If ctr = 10 Then
        output += "Thread.Sleep called..." + vbCrLf
        Thread.Sleep(5)
    End If
Next
Console.WriteLine(output)
' The example displays output like the following:
'       111
'       111
'       111
'       111
'       111
'       111
'       111
'       111
'       111
'       111
'       111
'       Thread.Sleep called...
'       143
'       143
'       143
'       143
'       143
'       143
'       143
'       143
'       143
'       143

Operaciones DateTime

Un cálculo mediante una DateTime estructura, como Add o Subtract, no modifica el valor de la estructura. En su lugar, el cálculo devuelve una nueva DateTime estructura cuyo valor es el resultado del cálculo.

Las operaciones de conversión entre zonas horarias (como entre utc y hora local, o entre una zona horaria y otra) tienen en cuenta el horario de verano, pero las operaciones de comparación y aritméticas no.

La DateTime propia estructura ofrece compatibilidad limitada para la conversión de una zona horaria a otra. Puede usar el ToLocalTime método para convertir UTC a hora local o puede usar el ToUniversalTime método para convertir de hora local a UTC. Sin embargo, hay disponible un conjunto completo de métodos de conversión de zona horaria en la TimeZoneInfo clase . Convierte la hora en cualquiera de las zonas horarias del mundo a la hora de cualquier otra zona horaria mediante estos métodos.

Los cálculos y comparaciones de DateTime objetos solo son significativos si los objetos representan horas en la misma zona horaria. Puede usar un TimeZoneInfo objeto para representar la zona horaria de un DateTime valor, aunque los dos están acoplados de forma flexible. Un DateTime objeto no tiene una propiedad que devuelve un objeto que representa la zona horaria del valor de fecha y hora. La propiedad Kind indica si un objeto DateTime representa UTC, hora local o no se especifica. En una aplicación que tenga en cuenta la zona horaria, debe confiar en algún mecanismo externo para determinar la zona horaria en la que se creó un DateTime objeto. Puede usar una estructura que encapsula el DateTime valor y el TimeZoneInfo objeto que representa la DateTime zona horaria del valor. Para obtener más información sobre el uso de UTC en cálculos y comparaciones con DateTime valores, vea Realizar operaciones aritméticas con fechas y horas.

Cada DateTime miembro usa implícitamente el calendario gregoriano para realizar su operación. Las excepciones son métodos que especifican implícitamente un calendario. Estos incluyen constructores que especifican un calendario y métodos con un parámetro derivado de IFormatProvider, como System.Globalization.DateTimeFormatInfo.

Las operaciones realizadas por miembros del tipo DateTime tienen en cuenta detalles como los años bisiestos y el número de días en un mes.

Valores y calendarios de DateTime

La biblioteca de clases de .NET incluye una serie de clases de calendario, todas las cuales se derivan de la Calendar clase . Son las siguientes:

Importante

Las eras en los calendarios japoneses se basan en el reinado del emperador y, por tanto, se espera que cambien. Por ejemplo, el 1 de mayo de 2019 marcó el principio de la era Reiwa en JapaneseCalendar y JapaneseLunisolarCalendar. Este cambio de era afecta a todas las aplicaciones que usan estos calendarios. Para obtener más información y determinar si las aplicaciones se ven afectadas, consulte Control de una nueva era en el calendario japonés en .NET. Para obtener información sobre cómo probar las aplicaciones en sistemas Windows para garantizar su preparación para el cambio de era, consulte Preparación de la aplicación para el cambio de la era japonesa. Para ver las características de .NET que admiten calendarios con varias eras y procedimientos recomendados al trabajar con calendarios que admiten varias eras, consulte Trabajar con eras.

Cada cultura utiliza un calendario por defecto definido por su propiedad CultureInfo.Calendar de solo lectura. Cada cultura puede soportar uno o más calendarios definidos por su propiedad de solo lectura CultureInfo.OptionalCalendars. El calendario usado actualmente por un objeto específico CultureInfo se define mediante su DateTimeFormatInfo.Calendar propiedad . Debe ser uno de los calendarios que se encuentran en la CultureInfo.OptionalCalendars matriz.

El calendario actual de una cultura se usa en todas las operaciones de formato para esa cultura. Por ejemplo, el calendario predeterminado de la cultura budista tailandesa es el calendario de la era budista tailandesa, representado por la ThaiBuddhistCalendar clase . Cuando se usa un CultureInfo objeto que representa la cultura budista tailandesa en una operación de formato de fecha y hora, el calendario de la era budista tailandesa se usa de forma predeterminada. El calendario gregoriano solo se usa si se cambia la propiedad de la referencia cultural DateTimeFormatInfo.Calendar, como se muestra en el ejemplo siguiente:

var thTH = new System.Globalization.CultureInfo("th-TH");
var value = new DateTime(2016, 5, 28);

Console.WriteLine(value.ToString(thTH));

thTH.DateTimeFormat.Calendar = new System.Globalization.GregorianCalendar();
Console.WriteLine(value.ToString(thTH));
// The example displays the following output:
//       28/5/2559 0:00:00
//       28/5/2016 0:00:00
let thTH = System.Globalization.CultureInfo "th-TH"
let value = DateTime(2016, 5, 28)

printfn $"{value.ToString thTH}"

thTH.DateTimeFormat.Calendar <- System.Globalization.GregorianCalendar()

printfn $"{value.ToString thTH}"

// The example displays the following output:
//       28/5/2559 0:00:00
//       28/5/2016 0:00:00
Dim thTH As New CultureInfo("th-TH")
Dim value As New DateTime(2016, 5, 28)

Console.WriteLine(value.ToString(thTH))

thTH.DateTimeFormat.Calendar = New GregorianCalendar()
Console.WriteLine(value.ToString(thTH))
' The example displays the following output:
'       28/5/2559 0:00:00
'       28/5/2016 0:00:00

El calendario actual de una referencia cultural también se usa en todas las operaciones de análisis de esa referencia cultural, como se muestra en el ejemplo siguiente.

var thTH = new System.Globalization.CultureInfo("th-TH");
var value = DateTime.Parse("28/05/2559", thTH);
Console.WriteLine(value.ToString(thTH));

thTH.DateTimeFormat.Calendar = new System.Globalization.GregorianCalendar();
Console.WriteLine(value.ToString(thTH));
// The example displays the following output:
//       28/5/2559 0:00:00
//       28/5/2016 0:00:00
let thTH = System.Globalization.CultureInfo "th-TH"
let value = DateTime.Parse("28/05/2559", thTH)
printfn $"{value.ToString thTH}"

thTH.DateTimeFormat.Calendar <- System.Globalization.GregorianCalendar()
printfn $"{value.ToString thTH}"

// The example displays the following output:
//       28/5/2559 0:00:00
//       28/5/2016 0:00:00
Private Sub ThaiBuddhistEraParse()
    Dim thTH As New CultureInfo("th-TH")
    Dim value As DateTime = DateTime.Parse("28/5/2559", thTH)
    Console.WriteLine(value.ToString(thTH))

    thTH.DateTimeFormat.Calendar = New GregorianCalendar()
    Console.WriteLine(value.ToString(thTH))
    ' The example displays the following output:
    '       28/5/2559 0:00:00
    '       28/5/2016 0:00:00
End Sub

Se crea una instancia de un DateTime valor utilizando los elementos de fecha y hora (número del año, mes y día) de un calendario específico, llamando a un constructor DateTime que incluye un calendar parámetro y pasándole un objeto Calendar que representa ese calendario. En el ejemplo siguiente se usan los elementos de fecha y hora del ThaiBuddhistCalendar calendario.

var thTH = new System.Globalization.CultureInfo("th-TH");
var dat = new DateTime(2559, 5, 28, thTH.DateTimeFormat.Calendar);
Console.WriteLine($"Thai Buddhist era date: {dat.ToString("d", thTH)}");
Console.WriteLine($"Gregorian date:   {dat:d}");
// The example displays the following output:
//       Thai Buddhist Era Date:  28/5/2559
//       Gregorian Date:     28/05/2016
let thTH = System.Globalization.CultureInfo "th-TH"
let dat = DateTime(2559, 5, 28, thTH.DateTimeFormat.Calendar)

printfn $"""Thai Buddhist era date: {dat.ToString("d", thTH)}"""
printfn $"Gregorian date:   {dat:d}"

// The example displays the following output:
//       Thai Buddhist Era Date:  28/5/2559
//       Gregorian Date:     28/05/2016
Dim thTH As New CultureInfo("th-TH")
Dim dat As New DateTime(2559, 5, 28, thTH.DateTimeFormat.Calendar)
Console.WriteLine($"Thai Buddhist Era date: {dat.ToString("d", thTH)}")
Console.WriteLine($"Gregorian date:   {dat:d}")
' The example displays the following output:
'       Thai Buddhist Era Date:  28/5/2559
'       Gregorian Date:     28/05/2016

DateTime constructores que no incluyen un calendar parámetro asumen que los elementos de fecha y hora se expresan como unidades en el calendario gregoriano.

Todas las demás DateTime propiedades y métodos usan el calendario gregoriano. Por ejemplo, la DateTime.Year propiedad devuelve el año en el calendario gregoriano y el DateTime.IsLeapYear(Int32) método supone que el year parámetro es un año en el calendario gregoriano. Cada DateTime miembro que usa el calendario gregoriano tiene un miembro correspondiente de la Calendar clase que usa un calendario específico. Por ejemplo, el Calendar.GetYear método devuelve el año en un calendario específico y el Calendar.IsLeapYear método interpreta el year parámetro como un número de año en un calendario específico. En el ejemplo siguiente se usan tanto los miembros de DateTime como los miembros correspondientes de la clase ThaiBuddhistCalendar.

var thTH = new System.Globalization.CultureInfo("th-TH");
var cal = thTH.DateTimeFormat.Calendar;
var dat = new DateTime(2559, 5, 28, cal);
Console.WriteLine("Using the Thai Buddhist Era calendar:");
Console.WriteLine($"Date: {dat.ToString("d", thTH)}");
Console.WriteLine($"Year: {cal.GetYear(dat)}");
Console.WriteLine($"Leap year: {cal.IsLeapYear(cal.GetYear(dat))}\n");

Console.WriteLine("Using the Gregorian calendar:");
Console.WriteLine($"Date: {dat:d}");
Console.WriteLine($"Year: {dat.Year}");
Console.WriteLine($"Leap year: {DateTime.IsLeapYear(dat.Year)}");
// The example displays the following output:
//       Using the Thai Buddhist Era calendar
//       Date :   28/5/2559
//       Year: 2559
//       Leap year :   True
//
//       Using the Gregorian calendar
//       Date :   28/05/2016
//       Year: 2016
//       Leap year :   True
let thTH = System.Globalization.CultureInfo "th-TH"
let cal = thTH.DateTimeFormat.Calendar
let dat = DateTime(2559, 5, 28, cal)
printfn "Using the Thai Buddhist Era calendar:"
printfn $"""Date: {dat.ToString("d", thTH)}"""
printfn $"Year: {cal.GetYear dat}"
printfn $"Leap year: {cal.IsLeapYear(cal.GetYear dat)}\n"

printfn "Using the Gregorian calendar:"
printfn $"Date: {dat:d}"
printfn $"Year: {dat.Year}"
printfn $"Leap year: {DateTime.IsLeapYear dat.Year}"

// The example displays the following output:
//       Using the Thai Buddhist Era calendar
//       Date :   28/5/2559
//       Year: 2559
//       Leap year :   True
//
//       Using the Gregorian calendar
//       Date :   28/05/2016
//       Year: 2016
//       Leap year :   True
Dim thTH As New CultureInfo("th-TH")
Dim cal As Calendar = thTH.DateTimeFormat.Calendar
Dim dat As New DateTime(2559, 5, 28, cal)
Console.WriteLine("Using the Thai Buddhist Era calendar:")
Console.WriteLine($"Date: {dat.ToString("d", thTH)}")
Console.WriteLine($"Year: {cal.GetYear(dat)}")
Console.WriteLine($"Leap year: {cal.IsLeapYear(cal.GetYear(dat))}")
Console.WriteLine()

Console.WriteLine("Using the Gregorian calendar:")
Console.WriteLine($"Date: {dat:d}")
Console.WriteLine($"Year: {dat.Year}")
Console.WriteLine($"Leap year: {DateTime.IsLeapYear(dat.Year)}")
' The example displays the following output:
'       Using the Thai Buddhist Era calendar
'       Date :   28/5/2559
'       Year: 2559
'       Leap year :   True
'
'       Using the Gregorian calendar
'       Date :   28/05/2016
'       Year: 2016
'       Leap year :   True

La DateTime estructura incluye una DayOfWeek propiedad que devuelve el día de la semana en el calendario gregoriano. No incluye un miembro que permita recuperar el número de semana del año. Para recuperar la semana del año, llame al método Calendar.GetWeekOfYear del calendario individual. Esto se muestra en el ejemplo siguiente.

var thTH = new System.Globalization.CultureInfo("th-TH");
var thCalendar = thTH.DateTimeFormat.Calendar;
var dat = new DateTime(1395, 8, 18, thCalendar);
Console.WriteLine("Using the Thai Buddhist Era calendar:");
Console.WriteLine($"Date: {dat.ToString("d", thTH)}");
Console.WriteLine($"Day of Week: {thCalendar.GetDayOfWeek(dat)}");
Console.WriteLine($"Week of year: {thCalendar.GetWeekOfYear(dat, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Sunday)}\n");

var greg = new System.Globalization.GregorianCalendar();
Console.WriteLine("Using the Gregorian calendar:");
Console.WriteLine($"Date: {dat:d}");
Console.WriteLine($"Day of Week: {dat.DayOfWeek}");
Console.WriteLine($"Week of year: {greg.GetWeekOfYear(dat, System.Globalization.CalendarWeekRule.FirstDay,DayOfWeek.Sunday)}");
// The example displays the following output:
//       Using the Thai Buddhist Era calendar
//       Date :  18/8/1395
//       Day of Week: Sunday
//       Week of year: 34
//
//       Using the Gregorian calendar
//       Date :  18/08/0852
//       Day of Week: Sunday
//       Week of year: 34
let thTH = System.Globalization.CultureInfo "th-TH"
let thCalendar = thTH.DateTimeFormat.Calendar
let dat = DateTime(1395, 8, 18, thCalendar)
printfn "Using the Thai Buddhist Era calendar:"
printfn $"""Date: {dat.ToString("d", thTH)}"""
printfn $"Day of Week: {thCalendar.GetDayOfWeek dat}"
printfn $"Week of year: {thCalendar.GetWeekOfYear(dat, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Sunday)}\n"

let greg = System.Globalization.GregorianCalendar()
printfn "Using the Gregorian calendar:"
printfn $"Date: {dat:d}"
printfn $"Day of Week: {dat.DayOfWeek}"
printfn $"Week of year: {greg.GetWeekOfYear(dat, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Sunday)}"

// The example displays the following output:
//       Using the Thai Buddhist Era calendar
//       Date :  18/8/1395
//       Day of Week: Sunday
//       Week of year: 34
//
//       Using the Gregorian calendar
//       Date :  18/08/0852
//       Day of Week: Sunday
//       Week of year: 34
Dim thTH As New CultureInfo("th-TH")
Dim thCalendar As Calendar = thTH.DateTimeFormat.Calendar
Dim dat As New DateTime(1395, 8, 18, thCalendar)
Console.WriteLine("Using the Thai Buddhist Era calendar:")
Console.WriteLine($"Date: {dat.ToString("d", thTH)}")
Console.WriteLine($"Day of Week: {thCalendar.GetDayOfWeek(dat)}")
Console.WriteLine($"Week of year: {thCalendar.GetWeekOfYear(dat, CalendarWeekRule.FirstDay, DayOfWeek.Sunday)}")
Console.WriteLine()

Dim greg As Calendar = New GregorianCalendar()
Console.WriteLine("Using the Gregorian calendar:")
Console.WriteLine($"Date: {dat:d}")
Console.WriteLine($"Day of Week: {dat.DayOfWeek}")
Console.WriteLine($"Week of year: {greg.GetWeekOfYear(dat, CalendarWeekRule.FirstDay, DayOfWeek.Sunday)}")
' The example displays the following output:
'       Using the Thai Buddhist Era calendar
'       Date :  18/8/1395
'       Day of Week: Sunday
'       Week of year: 34
'       
'       Using the Gregorian calendar
'       Date :  18/08/0852
'       Day of Week: Sunday
'       Week of year: 34

Para obtener más información sobre fechas y calendarios, vea Trabajar con calendarios.

Conservar valores DateTime

Puede conservar valores DateTime de las maneras siguientes:

Debe asegurarse de que la rutina que restaura los DateTime valores no pierde datos ni produce una excepción independientemente de la técnica que elija. Los valores DateTime deben redondearse. Es decir, el valor original y el valor restaurado deben ser los mismos. Y si el valor original DateTime representa un solo instante de tiempo, debe identificar el mismo momento de tiempo cuando se restaure.

Conservar los valores como cadenas de texto

Para restaurar DateTime correctamente los valores que se conservan como cadenas, siga estas reglas:

  • Haga las mismas suposiciones sobre el formato específico de la cultura cuando restaure la cadena que cuando la persistió. Para asegurarse de que una cadena se pueda restaurar en un sistema cuya cultura actual es diferente de la cultura del sistema en el que se guardó, llame a la sobrecarga ToString para guardar la cadena usando las convenciones de la cultura invariante. Llame a la sobrecarga Parse(String, IFormatProvider, DateTimeStyles) o TryParse(String, IFormatProvider, DateTimeStyles, DateTime) para restaurar la cadena utilizando las convenciones de la cultura invariante. Nunca utilice las sobrecargas ToString(), Parse(String) o TryParse(String, DateTime), que utilizan las convenciones de la cultura actual.

  • Si la fecha representa un solo momento de tiempo, asegúrese de que representa el mismo momento en el momento en que se restaura, incluso en una zona horaria diferente. Convierta el DateTime valor en Hora universal coordinada (UTC) antes de guardarlo o use DateTimeOffset.

El error más común que se comete al persistir valores DateTime como cadenas es confiar en las convenciones de formato de la cultura invariante o actual. Los problemas surgen si la cultura actual es diferente al guardar y restaurar las cadenas. En el ejemplo siguiente se muestran estos problemas. Guarda cinco fechas utilizando las normas de formato de la cultura actual, que en este caso es la inglesa (Estados Unidos). Restaura las fechas utilizando las convenciones de formato de otra cultura, que en este caso es el inglés (Reino Unido). Dado que las convenciones de formato de las dos referencias culturales son diferentes, no se pueden restaurar dos de las fechas y las tres fechas restantes se interpretan incorrectamente. Además, si los valores de fecha y hora originales representan momentos únicos en el tiempo, las horas restauradas son incorrectas porque se pierde la información de zona horaria.

public static void PersistAsLocalStrings()
{
    SaveLocalDatesAsString();
    RestoreLocalDatesFromString();
}

private static void SaveLocalDatesAsString()
{
    DateTime[] dates = { new DateTime(2014, 6, 14, 6, 32, 0),
                   new DateTime(2014, 7, 10, 23, 49, 0),
                   new DateTime(2015, 1, 10, 1, 16, 0),
                   new DateTime(2014, 12, 20, 21, 45, 0),
                   new DateTime(2014, 6, 2, 15, 14, 0) };
    string? output = null;

    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    for (int ctr = 0; ctr < dates.Length; ctr++)
    {
        Console.WriteLine(dates[ctr].ToString("f"));
        output += dates[ctr].ToString() + (ctr != dates.Length - 1 ? "|" : "");
    }
    var sw = new StreamWriter(filenameTxt);
    sw.Write(output);
    sw.Close();
    Console.WriteLine("Saved dates...");
}

private static void RestoreLocalDatesFromString()
{
    TimeZoneInfo.ClearCachedData();
    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
    StreamReader sr = new StreamReader(filenameTxt);
    string[] inputValues = sr.ReadToEnd().Split(new char[] { '|' },
                                                StringSplitOptions.RemoveEmptyEntries);
    sr.Close();
    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    foreach (var inputValue in inputValues)
    {
        DateTime dateValue;
        if (DateTime.TryParse(inputValue, out dateValue))
        {
            Console.WriteLine($"'{inputValue}' --> {dateValue:f}");
        }
        else
        {
            Console.WriteLine($"Cannot parse '{inputValue}'");
        }
    }
    Console.WriteLine("Restored dates...");
}
// When saved on an en-US system, the example displays the following output:
//       Current Time Zone: (UTC-08:00) Pacific Time (US & Canada)
//       The dates on an en-US system:
//       Saturday, June 14, 2014 6:32 AM
//       Thursday, July 10, 2014 11:49 PM
//       Saturday, January 10, 2015 1:16 AM
//       Saturday, December 20, 2014 9:45 PM
//       Monday, June 02, 2014 3:14 PM
//       Saved dates...
//
// When restored on an en-GB system, the example displays the following output:
//       Current Time Zone: (UTC) Dublin, Edinburgh, Lisbon, London
//       The dates on an en-GB system:
//       Cannot parse //6/14/2014 6:32:00 AM//
//       //7/10/2014 11:49:00 PM// --> 07 October 2014 23:49
//       //1/10/2015 1:16:00 AM// --> 01 October 2015 01:16
//       Cannot parse //12/20/2014 9:45:00 PM//
//       //6/2/2014 3:14:00 PM// --> 06 February 2014 15:14
//       Restored dates...
let saveLocalDatesAsString () =
    let dates = 
        [ DateTime(2014, 6, 14, 6, 32, 0)
          DateTime(2014, 7, 10, 23, 49, 0)
          DateTime(2015, 1, 10, 1, 16, 0)
          DateTime(2014, 12, 20, 21, 45, 0)
          DateTime(2014, 6, 2, 15, 14, 0) ]

    printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
    printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"

    let output =
        [ for date in dates do
            printfn $"{date}"
            string date ]
        |> String.concat "|"

    use sw = new StreamWriter(filenameTxt)
    sw.Write output
    printfn "Saved dates..."

let restoreLocalDatesFromString () =
    TimeZoneInfo.ClearCachedData()
    printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
    Thread.CurrentThread.CurrentCulture <- CultureInfo.CreateSpecificCulture "en-GB"

    use sr = new StreamReader(filenameTxt)
    let inputValues = 
        sr.ReadToEnd().Split('|', StringSplitOptions.RemoveEmptyEntries)

    printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"

    for inputValue in inputValues do
        match DateTime.TryParse inputValue with
        | true, dateValue ->
            printfn $"'{inputValue}' --> {dateValue:f}"
        | _ ->
            printfn $"Cannot parse '{inputValue}'"

    printfn "Restored dates..."

let persistAsLocalStrings () =
    saveLocalDatesAsString ()
    restoreLocalDatesFromString ()

// When saved on an en-US system, the example displays the following output:
//       Current Time Zone: (UTC-08:00) Pacific Time (US & Canada)
//       The dates on an en-US system:
//       Saturday, June 14, 2014 6:32 AM
//       Thursday, July 10, 2014 11:49 PM
//       Saturday, January 10, 2015 1:16 AM
//       Saturday, December 20, 2014 9:45 PM
//       Monday, June 02, 2014 3:14 PM
//       Saved dates...
//
// When restored on an en-GB system, the example displays the following output:
//       Current Time Zone: (UTC) Dublin, Edinburgh, Lisbon, London
//       The dates on an en-GB system:
//       Cannot parse //6/14/2014 6:32:00 AM//
//       //7/10/2014 11:49:00 PM// --> 07 October 2014 23:49
//       //1/10/2015 1:16:00 AM// --> 01 October 2015 01:16
//       Cannot parse //12/20/2014 9:45:00 PM//
//       //6/2/2014 3:14:00 PM// --> 06 February 2014 15:14
//       Restored dates...

Para redondear valores DateTime con éxito, siga estos pasos:

  1. Si los valores representan momentos únicos de tiempo, conviértelos de la hora local a UTC llamando al ToUniversalTime método .
  2. Convierta las fechas a sus representaciones de cadena llamando a la sobrecarga ToString(String, IFormatProvider) o String.Format(IFormatProvider, String, Object[]). Utilice las convenciones de formato de la cultura invariable especificando CultureInfo.InvariantCulture como el argumento provider. Especifique que el valor debe realizar un recorrido de ida y vuelta mediante la cadena de formato estándar "O" o "R".

Para restaurar los valores persistentes DateTime sin pérdida de datos, siga estos pasos:

  1. Analice los datos llamando a la sobrecarga ParseExact o TryParseExact. Especifique CultureInfo.InvariantCulture como el argumento provider y use la misma cadena de formato estándar que empleó para el argumento format durante la conversión. Incluya el DateTimeStyles.RoundtripKind valor en el styles argumento .
  2. Si los DateTime valores representan momentos únicos en el tiempo, llame al ToLocalTime método para convertir la fecha analizada de UTC a hora local.

En el ejemplo siguiente se usa la referencia cultural invariable y la cadena de formato estándar "O" para asegurarse de que los DateTime valores guardados y restaurados representan el mismo momento en el tiempo, independientemente del sistema, la referencia cultural o la zona horaria de los sistemas de origen y destino.

public static void PersistAsInvariantStrings()
{
    SaveDatesAsInvariantStrings();
    RestoreDatesAsInvariantStrings();
}

private static void SaveDatesAsInvariantStrings()
{
    DateTime[] dates = { new DateTime(2014, 6, 14, 6, 32, 0),
                   new DateTime(2014, 7, 10, 23, 49, 0),
                   new DateTime(2015, 1, 10, 1, 16, 0),
                   new DateTime(2014, 12, 20, 21, 45, 0),
                   new DateTime(2014, 6, 2, 15, 14, 0) };
    string? output = null;

    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    for (int ctr = 0; ctr < dates.Length; ctr++)
    {
        Console.WriteLine(dates[ctr].ToString("f"));
        output += dates[ctr].ToUniversalTime().ToString("O", CultureInfo.InvariantCulture)
                  + (ctr != dates.Length - 1 ? "|" : "");
    }
    var sw = new StreamWriter(filenameTxt);
    sw.Write(output);
    sw.Close();
    Console.WriteLine("Saved dates...");
}

private static void RestoreDatesAsInvariantStrings()
{
    TimeZoneInfo.ClearCachedData();
    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
    StreamReader sr = new StreamReader(filenameTxt);
    string[] inputValues = sr.ReadToEnd().Split(new char[] { '|' },
                                                StringSplitOptions.RemoveEmptyEntries);
    sr.Close();
    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    foreach (var inputValue in inputValues)
    {
        DateTime dateValue;
        if (DateTime.TryParseExact(inputValue, "O", CultureInfo.InvariantCulture,
                              DateTimeStyles.RoundtripKind, out dateValue))
        {
            Console.WriteLine($"'{inputValue}' --> {dateValue.ToLocalTime():f}");
        }
        else
        {
            Console.WriteLine($"Cannot parse '{inputValue}'");
        }
    }
    Console.WriteLine("Restored dates...");
}
// When saved on an en-US system, the example displays the following output:
//       Current Time Zone: (UTC-08:00) Pacific Time (US & Canada)
//       The dates on an en-US system:
//       Saturday, June 14, 2014 6:32 AM
//       Thursday, July 10, 2014 11:49 PM
//       Saturday, January 10, 2015 1:16 AM
//       Saturday, December 20, 2014 9:45 PM
//       Monday, June 02, 2014 3:14 PM
//       Saved dates...
//
// When restored on an en-GB system, the example displays the following output:
//       Current Time Zone: (UTC) Dublin, Edinburgh, Lisbon, London
//       The dates on an en-GB system:
//       '2014-06-14T13:32:00.0000000Z' --> 14 June 2014 14:32
//       '2014-07-11T06:49:00.0000000Z' --> 11 July 2014 07:49
//       '2015-01-10T09:16:00.0000000Z' --> 10 January 2015 09:16
//       '2014-12-21T05:45:00.0000000Z' --> 21 December 2014 05:45
//       '2014-06-02T22:14:00.0000000Z' --> 02 June 2014 23:14
//       Restored dates...
let saveDatesAsInvariantStrings () =
    let dates = 
        [ DateTime(2014, 6, 14, 6, 32, 0)
          DateTime(2014, 7, 10, 23, 49, 0)
          DateTime(2015, 1, 10, 1, 16, 0)
          DateTime(2014, 12, 20, 21, 45, 0)
          DateTime(2014, 6, 2, 15, 14, 0) ]

    printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
    printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"

    let output =
        [ for date in dates do
            printfn $"{date:f}"
            date.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) ]
        |> String.concat "|"

    use sw = new StreamWriter(filenameTxt)
    sw.Write output
    printfn "Saved dates..."

let restoreDatesAsInvariantStrings () =
    TimeZoneInfo.ClearCachedData()
    printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
    Thread.CurrentThread.CurrentCulture <- CultureInfo.CreateSpecificCulture "en-GB"
    
    use sr = new StreamReader(filenameTxt)
    let inputValues = 
        sr.ReadToEnd().Split('|', StringSplitOptions.RemoveEmptyEntries)

    printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"

    for inputValue in inputValues do
        match DateTime.TryParseExact(inputValue, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind) with
        | true, dateValue ->
            printfn $"'{inputValue}' --> {dateValue.ToLocalTime():f}"
        | _ ->
            printfn $"Cannot parse '{inputValue}'"

    printfn "Restored dates..."

let persistAsInvariantStrings () =
    saveDatesAsInvariantStrings ()
    restoreDatesAsInvariantStrings ()

// When saved on an en-US system, the example displays the following output:
//       Current Time Zone: (UTC-08:00) Pacific Time (US & Canada)
//       The dates on an en-US system:
//       Saturday, June 14, 2014 6:32 AM
//       Thursday, July 10, 2014 11:49 PM
//       Saturday, January 10, 2015 1:16 AM
//       Saturday, December 20, 2014 9:45 PM
//       Monday, June 02, 2014 3:14 PM
//       Saved dates...
//
// When restored on an en-GB system, the example displays the following output:
//       Current Time Zone: (UTC) Dublin, Edinburgh, Lisbon, London
//       The dates on an en-GB system:
//       '2014-06-14T13:32:00.0000000Z' --> 14 June 2014 14:32
//       '2014-07-11T06:49:00.0000000Z' --> 11 July 2014 07:49
//       '2015-01-10T09:16:00.0000000Z' --> 10 January 2015 09:16
//       '2014-12-21T05:45:00.0000000Z' --> 21 December 2014 05:45
//       '2014-06-02T22:14:00.0000000Z' --> 02 June 2014 23:14
//       Restored dates...

Mantener valores como enteros

Puede persistir una fecha y hora como un valor Int64 que representa un número de ticks. En este caso, no es necesario tener en cuenta la cultura de los sistemas en los que los valores DateTime se conservan y restauran.

Para conservar un DateTime valor como un entero:

  1. Si los DateTime valores representan momentos únicos en el tiempo, conviértelos a UTC llamando al ToUniversalTime método .
  2. Recupere el número de ticks representados por el valor DateTime de su propiedad Ticks.

Para restaurar un DateTime valor que se ha conservado como un entero:

  1. Cree una instancia de un nuevo DateTime objeto pasando el Int64 valor al DateTime(Int64) constructor.
  2. Si el DateTime valor representa un momento en el tiempo, conviértelo de UTC a la hora local llamando al ToLocalTime método .

El siguiente ejemplo persiste una matriz de valores DateTime como enteros en un sistema en la zona horaria del Pacífico de Estados Unidos. Lo restaura en un sistema en la zona UTC. El archivo que contiene los enteros incluye un Int32 valor que indica el número total de Int64 valores que lo siguen inmediatamente.

public static void PersistAsIntegers()
{
    SaveDatesAsInts();
    RestoreDatesAsInts();
}

private static void SaveDatesAsInts()
{
    DateTime[] dates = { new DateTime(2014, 6, 14, 6, 32, 0),
                   new DateTime(2014, 7, 10, 23, 49, 0),
                   new DateTime(2015, 1, 10, 1, 16, 0),
                   new DateTime(2014, 12, 20, 21, 45, 0),
                   new DateTime(2014, 6, 2, 15, 14, 0) };

    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    var ticks = new long[dates.Length];
    for (int ctr = 0; ctr < dates.Length; ctr++)
    {
        Console.WriteLine(dates[ctr].ToString("f"));
        ticks[ctr] = dates[ctr].ToUniversalTime().Ticks;
    }
    var fs = new FileStream(filenameInts, FileMode.Create);
    var bw = new BinaryWriter(fs);
    bw.Write(ticks.Length);
    foreach (var tick in ticks)
        bw.Write(tick);

    bw.Close();
    Console.WriteLine("Saved dates...");
}

private static void RestoreDatesAsInts()
{
    TimeZoneInfo.ClearCachedData();
    Console.WriteLine($"Current Time Zone: {TimeZoneInfo.Local.DisplayName}");
    Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
    FileStream fs = new FileStream(filenameInts, FileMode.Open);
    BinaryReader br = new BinaryReader(fs);
    int items;
    DateTime[] dates;

    try
    {
        items = br.ReadInt32();
        dates = new DateTime[items];

        for (int ctr = 0; ctr < items; ctr++)
        {
            long ticks = br.ReadInt64();
            dates[ctr] = new DateTime(ticks).ToLocalTime();
        }
    }
    catch (EndOfStreamException)
    {
        Console.WriteLine("File corruption detected. Unable to restore data...");
        return;
    }
    catch (IOException)
    {
        Console.WriteLine("Unspecified I/O error. Unable to restore data...");
        return;
    }
    // Thrown during array initialization.
    catch (OutOfMemoryException)
    {
        Console.WriteLine("File corruption detected. Unable to restore data...");
        return;
    }
    finally
    {
        br.Close();
    }

    Console.WriteLine($"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    foreach (var value in dates)
        Console.WriteLine(value.ToString("f"));

    Console.WriteLine("Restored dates...");
}
// When saved on an en-US system, the example displays the following output:
//       Current Time Zone: (UTC-08:00) Pacific Time (US & Canada)
//       The dates on an en-US system:
//       Saturday, June 14, 2014 6:32 AM
//       Thursday, July 10, 2014 11:49 PM
//       Saturday, January 10, 2015 1:16 AM
//       Saturday, December 20, 2014 9:45 PM
//       Monday, June 02, 2014 3:14 PM
//       Saved dates...
//
// When restored on an en-GB system, the example displays the following output:
//       Current Time Zone: (UTC) Dublin, Edinburgh, Lisbon, London
//       The dates on an en-GB system:
//       14 June 2014 14:32
//       11 July 2014 07:49
//       10 January 2015 09:16
//       21 December 2014 05:45
//       02 June 2014 23:14
//       Restored dates...
let saveDatesAsInts () =
    let dates = 
        [ DateTime(2014, 6, 14, 6, 32, 0)
          DateTime(2014, 7, 10, 23, 49, 0)
          DateTime(2015, 1, 10, 1, 16, 0)
          DateTime(2014, 12, 20, 21, 45, 0)
          DateTime(2014, 6, 2, 15, 14, 0) ]

    printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
    printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"
    let ticks =
        [| for date in dates do
            printfn $"{date:f}"
            date.ToUniversalTime().Ticks |]
    use fs = new FileStream(filenameInts, FileMode.Create)
    use bw = new BinaryWriter(fs)
    bw.Write ticks.Length

    for tick in ticks do
        bw.Write tick

    printfn "Saved dates..."

let restoreDatesAsInts () =
    TimeZoneInfo.ClearCachedData()
    printfn $"Current Time Zone: {TimeZoneInfo.Local.DisplayName}"
    Thread.CurrentThread.CurrentCulture <- CultureInfo.CreateSpecificCulture "en-GB"
    use fs = new FileStream(filenameInts, FileMode.Open)
    use br = new BinaryReader(fs)

    try
        let items = br.ReadInt32()
        let dates =
            [| for _ in 0..items do
                let ticks = br.ReadInt64()
                DateTime(ticks).ToLocalTime() |]

        printfn $"The dates on an {Thread.CurrentThread.CurrentCulture.Name} system:"
        for value in dates do
            printfn $"{value:f}"
    with 
    | :? EndOfStreamException ->
        printfn "File corruption detected. Unable to restore data..."
    | :? IOException ->
        printfn "Unspecified I/O error. Unable to restore data..."
    // Thrown during array initialization.
    | :? OutOfMemoryException ->
        printfn"File corruption detected. Unable to restore data..."

    printfn "Restored dates..."

let persistAsIntegers () =
    saveDatesAsInts ()
    restoreDatesAsInts ()

// When saved on an en-US system, the example displays the following output:
//       Current Time Zone: (UTC-08:00) Pacific Time (US & Canada)
//       The dates on an en-US system:
//       Saturday, June 14, 2014 6:32 AM
//       Thursday, July 10, 2014 11:49 PM
//       Saturday, January 10, 2015 1:16 AM
//       Saturday, December 20, 2014 9:45 PM
//       Monday, June 02, 2014 3:14 PM
//       Saved dates...
//
// When restored on an en-GB system, the example displays the following output:
//       Current Time Zone: (UTC) Dublin, Edinburgh, Lisbon, London
//       The dates on an en-GB system:
//       14 June 2014 14:32
//       11 July 2014 07:49
//       10 January 2015 09:16
//       21 December 2014 05:45
//       02 June 2014 23:14
//       Restored dates...

Serializar valores de fecha y hora

Puede conservar DateTime los valores mediante la serialización en una secuencia o archivo y, a continuación, restaurarlos a través de la deserialización. DateTime los datos se serializan en algún formato de objeto especificado. Los objetos se restauran cuando se deserializan. Un formateador o serializador, como JsonSerializer o XmlSerializer, controla el proceso de serialización y deserialización. Para obtener más información sobre la serialización y los tipos de serialización admitidos por .NET, consulte Serialización.

En el ejemplo siguiente se usa la XmlSerializer clase para serializar y deserializar DateTime valores. Los valores representan todos los días bisiestos del siglo XXI. La salida representa el resultado si el ejemplo se ejecuta en un sistema cuya referencia cultural actual es inglés (Reino Unido). Dado que ha deserializado el propio objeto DateTime, el código no tiene que gestionar las diferencias culturales en los formatos de fecha y hora.

public static void PersistAsXML()
{
    // Serialize the data.
    var leapYears = new List<DateTime>();
    for (int year = 2000; year <= 2100; year += 4)
    {
        if (DateTime.IsLeapYear(year))
            leapYears.Add(new DateTime(year, 2, 29));
    }
    DateTime[] dateArray = leapYears.ToArray();

    var serializer = new XmlSerializer(dateArray.GetType());
    TextWriter sw = new StreamWriter(filenameXml);

    try
    {
        serializer.Serialize(sw, dateArray);
    }
    catch (InvalidOperationException e)
    {
        Console.WriteLine(e.InnerException?.Message);
    }
    finally
    {
        if (sw != null) sw.Close();
    }

    // Deserialize the data.
    DateTime[]? deserializedDates;
    using (var fs = new FileStream(filenameXml, FileMode.Open))
    {
        deserializedDates = (DateTime[]?)serializer.Deserialize(fs);
    }

    // Display the dates.
    Console.WriteLine($"Leap year days from 2000-2100 on an {Thread.CurrentThread.CurrentCulture.Name} system:");
    int nItems = 0;
    if (deserializedDates is not null)
    {
        foreach (var dat in deserializedDates)
        {
            Console.Write($"   {dat:d}     ");
            nItems++;
            if (nItems % 5 == 0)
                Console.WriteLine();
        }
    }
}
// The example displays the following output:
//    Leap year days from 2000-2100 on an en-GB system:
//       29/02/2000       29/02/2004       29/02/2008       29/02/2012       29/02/2016
//       29/02/2020       29/02/2024       29/02/2028       29/02/2032       29/02/2036
//       29/02/2040       29/02/2044       29/02/2048       29/02/2052       29/02/2056
//       29/02/2060       29/02/2064       29/02/2068       29/02/2072       29/02/2076
//       29/02/2080       29/02/2084       29/02/2088       29/02/2092       29/02/2096
let persistAsXML () =
    // Serialize the data.
    let leapYears =
        [| for year in 2000..4..2100 do
            if DateTime.IsLeapYear year then
                DateTime(year, 2, 29) |]

    let serializer = XmlSerializer(leapYears.GetType())
    use sw = new StreamWriter(filenameXml)

    try
        serializer.Serialize(sw, leapYears)
    with :? InvalidOperationException as e ->
        printfn $"{e.InnerException.Message}"

    // Deserialize the data.
    use fs = new FileStream(filenameXml, FileMode.Open)
        
    let deserializedDates = serializer.Deserialize fs :?> DateTime []

    // Display the dates.
    printfn $"Leap year days from 2000-2100 on an {Thread.CurrentThread.CurrentCulture.Name} system:"
    
    let mutable nItems = 0
    for dat in deserializedDates do
        printf $"   {dat:d}     "
        nItems <- nItems + 1
        if nItems % 5 = 0 then
            printfn ""

// The example displays the following output:
//    Leap year days from 2000-2100 on an en-GB system:
//       29/02/2000       29/02/2004       29/02/2008       29/02/2012       29/02/2016
//       29/02/2020       29/02/2024       29/02/2028       29/02/2032       29/02/2036
//       29/02/2040       29/02/2044       29/02/2048       29/02/2052       29/02/2056
//       29/02/2060       29/02/2064       29/02/2068       29/02/2072       29/02/2076
//       29/02/2080       29/02/2084       29/02/2088       29/02/2092       29/02/2096

En el ejemplo anterior no se incluye información de hora. Si un DateTime valor representa un momento en el tiempo y se expresa como una hora local, conviértelo de hora local a UTC antes de serializarlo llamando al ToUniversalTime método . Después de deserializarla, conviértela de UTC a hora local llamando al ToLocalTime método .

DateTime frente a TimeSpan

Los tipos de valor DateTime y TimeSpan difieren en que un DateTime representa un instante en el tiempo, mientras que un TimeSpan representa un intervalo de tiempo. Puede restar una instancia de DateTime de otra para obtener el objeto TimeSpan que represente el intervalo de tiempo entre ellos. O bien, podría agregar un positivo TimeSpan al actual DateTime para obtener un DateTime valor que represente una fecha futura.

Puede agregar o restar un intervalo de tiempo de un DateTime objeto . Los intervalos de tiempo pueden ser negativos o positivos, y se pueden expresar en unidades como ticks, segundos o representarse como un objeto TimeSpan.

Comparar por igualdad dentro de la tolerancia

Las comparaciones de igualdad para los valores de DateTime son exactas. Para que se consideren iguales, dos valores deben expresarse como el mismo número de ticks. Esa precisión suele ser innecesaria o incluso incorrecta para muchas aplicaciones. A menudo, quiere probar si DateTime los objetos son aproximadamente iguales.

En el ejemplo siguiente se muestra cómo comparar valores aproximadamente equivalentes DateTime . Acepta un pequeño margen de diferencia al declararlos iguales.

public static bool RoughlyEquals(DateTime time, DateTime timeWithWindow, int windowInSeconds, int frequencyInSeconds)
{
    long delta = (long)((TimeSpan)(timeWithWindow - time)).TotalSeconds % frequencyInSeconds;
    delta = delta > windowInSeconds ? frequencyInSeconds - delta : delta;
    return Math.Abs(delta) < windowInSeconds;
}

public static void TestRoughlyEquals()
{
    int window = 10;
    int freq = 60 * 60 * 2; // 2 hours;

    DateTime d1 = DateTime.Now;

    DateTime d2 = d1.AddSeconds(2 * window);
    DateTime d3 = d1.AddSeconds(-2 * window);
    DateTime d4 = d1.AddSeconds(window / 2);
    DateTime d5 = d1.AddSeconds(-window / 2);

    DateTime d6 = (d1.AddHours(2)).AddSeconds(2 * window);
    DateTime d7 = (d1.AddHours(2)).AddSeconds(-2 * window);
    DateTime d8 = (d1.AddHours(2)).AddSeconds(window / 2);
    DateTime d9 = (d1.AddHours(2)).AddSeconds(-window / 2);

    Console.WriteLine($"d1 ({d1}) ~= d1 ({d1}): {RoughlyEquals(d1, d1, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d2 ({d2}): {RoughlyEquals(d1, d2, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d3 ({d3}): {RoughlyEquals(d1, d3, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d4 ({d4}): {RoughlyEquals(d1, d4, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d5 ({d5}): {RoughlyEquals(d1, d5, window, freq)}");

    Console.WriteLine($"d1 ({d1}) ~= d6 ({d6}): {RoughlyEquals(d1, d6, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d7 ({d7}): {RoughlyEquals(d1, d7, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d8 ({d8}): {RoughlyEquals(d1, d8, window, freq)}");
    Console.WriteLine($"d1 ({d1}) ~= d9 ({d9}): {RoughlyEquals(d1, d9, window, freq)}");
}
// The example displays output similar to the following:
//    d1 (1/28/2010 9:01:26 PM) ~= d1 (1/28/2010 9:01:26 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d2 (1/28/2010 9:01:46 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d3 (1/28/2010 9:01:06 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d4 (1/28/2010 9:01:31 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d5 (1/28/2010 9:01:21 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d6 (1/28/2010 11:01:46 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d7 (1/28/2010 11:01:06 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d8 (1/28/2010 11:01:31 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d9 (1/28/2010 11:01:21 PM): True
let roughlyEquals (time: DateTime) (timeWithWindow: DateTime) windowInSeconds frequencyInSeconds =
    let delta = 
        int64 (timeWithWindow - time).TotalSeconds % frequencyInSeconds
    
    let delta = if delta > windowInSeconds then frequencyInSeconds - delta else delta
    abs delta < windowInSeconds

let testRoughlyEquals () =
    let window = 10
    let window' = 10.
    let freq = 60 * 60 * 2 // 2 hours

    let d1 = DateTime.Now

    let d2 = d1.AddSeconds(2. * window')
    let d3 = d1.AddSeconds(-2. * window')
    let d4 = d1.AddSeconds(window' / 2.)
    let d5 = d1.AddSeconds(-window' / 2.)

    let d6 = (d1.AddHours 2).AddSeconds(2. * window')
    let d7 = (d1.AddHours 2).AddSeconds(-2. * window')
    let d8 = (d1.AddHours 2).AddSeconds(window' / 2.)
    let d9 = (d1.AddHours 2).AddSeconds(-window' / 2.)

    printfn $"d1 ({d1}) ~= d1 ({d1}): {roughlyEquals d1 d1 window freq}"
    printfn $"d1 ({d1}) ~= d2 ({d2}): {roughlyEquals d1 d2 window freq}"
    printfn $"d1 ({d1}) ~= d3 ({d3}): {roughlyEquals d1 d3 window freq}"
    printfn $"d1 ({d1}) ~= d4 ({d4}): {roughlyEquals d1 d4 window freq}"
    printfn $"d1 ({d1}) ~= d5 ({d5}): {roughlyEquals d1 d5 window freq}"

    printfn $"d1 ({d1}) ~= d6 ({d6}): {roughlyEquals d1 d6 window freq}"
    printfn $"d1 ({d1}) ~= d7 ({d7}): {roughlyEquals d1 d7 window freq}"
    printfn $"d1 ({d1}) ~= d8 ({d8}): {roughlyEquals d1 d8 window freq}"
    printfn $"d1 ({d1}) ~= d9 ({d9}): {roughlyEquals d1 d9 window freq}"

// The example displays output similar to the following:
//    d1 (1/28/2010 9:01:26 PM) ~= d1 (1/28/2010 9:01:26 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d2 (1/28/2010 9:01:46 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d3 (1/28/2010 9:01:06 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d4 (1/28/2010 9:01:31 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d5 (1/28/2010 9:01:21 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d6 (1/28/2010 11:01:46 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d7 (1/28/2010 11:01:06 PM): False
//    d1 (1/28/2010 9:01:26 PM) ~= d8 (1/28/2010 11:01:31 PM): True
//    d1 (1/28/2010 9:01:26 PM) ~= d9 (1/28/2010 11:01:21 PM): True
Public Shared Function RoughlyEquals(time As DateTime, timeWithWindow As DateTime,
                             windowInSeconds As Integer,
                             frequencyInSeconds As Integer) As Boolean
    Dim delta As Long = (timeWithWindow.Subtract(time)).TotalSeconds _
                                            Mod frequencyInSeconds

    If delta > windowInSeconds Then
        delta = frequencyInSeconds - delta
    End If

    Return Math.Abs(delta) < windowInSeconds
End Function

Public Shared Sub TestRoughlyEquals()
    Dim window As Integer = 10
    Dim freq As Integer = 60 * 60 * 2 ' 2 hours;
    Dim d1 As DateTime = DateTime.Now

    Dim d2 As DateTime = d1.AddSeconds(2 * window)
    Dim d3 As DateTime = d1.AddSeconds(-2 * window)
    Dim d4 As DateTime = d1.AddSeconds(window / 2)
    Dim d5 As DateTime = d1.AddSeconds(-window / 2)

    Dim d6 As DateTime = d1.AddHours(2).AddSeconds(2 * window)
    Dim d7 As DateTime = d1.AddHours(2).AddSeconds(-2 * window)
    Dim d8 As DateTime = d1.AddHours(2).AddSeconds(window / 2)
    Dim d9 As DateTime = d1.AddHours(2).AddSeconds(-window / 2)

    Console.WriteLine($"d1 ({d1}) ~= d1 ({d1}): {RoughlyEquals(d1, d1, window, freq)}")
    Console.WriteLine($"d1 ({d1}) ~= d2 ({d2}): {RoughlyEquals(d1, d2, window, freq)}")
    Console.WriteLine($"d1 ({d1}) ~= d3 ({d3}): {RoughlyEquals(d1, d3, window, freq)}")
    Console.WriteLine($"d1 ({d1}) ~= d4 ({d4}): {RoughlyEquals(d1, d4, window, freq)}")
    Console.WriteLine($"d1 ({d1}) ~= d5 ({d5}): {RoughlyEquals(d1, d5, window, freq)}")

    Console.WriteLine($"d1 ({d1}) ~= d6 ({d6}): {RoughlyEquals(d1, d6, window, freq)}")
    Console.WriteLine($"d1 ({d1}) ~= d7 ({d7}): {RoughlyEquals(d1, d7, window, freq)}")
    Console.WriteLine($"d1 ({d1}) ~= d8 ({d8}): {RoughlyEquals(d1, d8, window, freq)}")
    Console.WriteLine($"d1 ({d1}) ~= d9 ({d9}): {RoughlyEquals(d1, d9, window, freq)}")
End Sub
' The example displays output similar to the following:
'    d1 (1/28/2010 9:01:26 PM) ~= d1 (1/28/2010 9:01:26 PM): True
'    d1 (1/28/2010 9:01:26 PM) ~= d2 (1/28/2010 9:01:46 PM): False
'    d1 (1/28/2010 9:01:26 PM) ~= d3 (1/28/2010 9:01:06 PM): False
'    d1 (1/28/2010 9:01:26 PM) ~= d4 (1/28/2010 9:01:31 PM): True
'    d1 (1/28/2010 9:01:26 PM) ~= d5 (1/28/2010 9:01:21 PM): True
'    d1 (1/28/2010 9:01:26 PM) ~= d6 (1/28/2010 11:01:46 PM): False
'    d1 (1/28/2010 9:01:26 PM) ~= d7 (1/28/2010 11:01:06 PM): False
'    d1 (1/28/2010 9:01:26 PM) ~= d8 (1/28/2010 11:01:31 PM): True
'    d1 (1/28/2010 9:01:26 PM) ~= d9 (1/28/2010 11:01:21 PM): True

Consideraciones de interoperabilidad COM

Se dice que un valor DateTime que se transfiere a una aplicación COM, y luego vuelve a ser transferido a una aplicación administrada, realiza un viaje de ida y vuelta. Sin embargo, un valor DateTime que especifica solo un tiempo no round-trip como se podría esperar.

Si solo se redondea una hora, por ejemplo las 3 de la tarde, la fecha y hora finales serán 30 de diciembre de 1899 C.E. a las 3:00 P.M., en lugar de 1 de enero de 0001 C.E. a las 3:00 P.M. .NET y COM asumen una fecha por defecto cuando solo se especifica una hora. Sin embargo, el sistema COM asume una fecha base del 30 de diciembre de 1899 C.E., mientras que .NET supone una fecha base del 1 de enero de 0001 C.E.

Cuando solo se pasa un tiempo de .NET a COM, se lleva a cabo un procesamiento especial que lo convierte al formato usado por COM. Cuando solo se pasa una hora de COM a .NET, no se realiza ningún procesamiento especial porque eso dañaría las fechas y horas legítimas en o antes del 30 de diciembre de 1899. Si una fecha inicia su recorrido de ida y vuelta desde COM, .NET y COM conservan la fecha.

El comportamiento de .NET y COM implica que si su aplicación realiza una conversión de ida y vuelta de un DateTime que únicamente especifica una hora, su aplicación debe recordar modificar o ignorar la fecha errónea del objeto DateTime final.