Fecha y hora frente a DateTimeOffset

Resuelto David Reis asked hace 14 años • 10 respuestas

¿ Cuál es la diferencia entre a DateTimey a DateTimeOffsety cuándo se debe utilizar?


Actualmente, tenemos una forma estándar de tratar con .NET DateTimeteniendo en cuenta la zona horaria: cada vez que producimos un archivo, DateTimelo hacemos en UTC (por ejemplo, usandoDateTime.UtcNow ) y cada vez que mostramos uno, convertimos de UTC a la hora local del usuario. .

Eso funciona bien, pero he estado leyendo sobre DateTimeOffsetcómo captura la hora local y UTC en el objeto mismo.

David Reis avatar Dec 02 '10 09:12 David Reis
Aceptado

DateTimeOffsetes una representación del tiempo instantáneo (también conocido como tiempo absoluto ). Con esto me refiero a un momento en el tiempo que es universal para todos (sin tener en cuenta los segundos intercalares ni los efectos relativistas de la dilatación del tiempo ). Otra forma de representar el tiempo instantáneo es con un DateTimedónde .Kindestá DateTimeKind.Utc.

Esto es distinto del tiempo del calendario (también conocido como tiempo civil ), que es una posición en el calendario de alguien, y existen muchos calendarios diferentes en todo el mundo. A estos calendarios los llamamos zonas horarias . La hora del calendario está representada por un DateTimedónde .Kindes DateTimeKind.Unspecifiedo DateTimeKind.Local. Y .Localsolo tiene sentido en escenarios en los que se tiene una comprensión implícita de dónde está ubicada la computadora que utiliza el resultado. (Por ejemplo, la estación de trabajo de un usuario)

Entonces, ¿por qué DateTimeOffseten lugar de UTC DateTime? Se trata de perspectiva. Usemos una analogía: haremos como si fuéramos fotógrafos.

Imagínese que está parado en la línea de tiempo de un calendario, apuntando con una cámara a una persona en la línea de tiempo instantánea colocada frente a usted. Usted alinea su cámara de acuerdo con las reglas de su zona horaria, que cambian periódicamente debido al horario de verano o debido a otros cambios en la definición legal de su zona horaria. (No tienes mano firme, por lo que tu cámara tiembla).

La persona parada en la foto vería el ángulo desde el que vino la cámara. Si otros estuvieran tomando fotografías, podrían ser desde diferentes ángulos. Esto es lo que representa la Offsetparte del DateTimeOffset.

Entonces, si etiqueta su cámara como "Hora del Este", a veces apuntará desde -5 y otras veces apuntará desde -4. Hay cámaras en todo el mundo, todas etiquetadas con cosas diferentes y todas apuntando a la misma línea de tiempo instantánea desde diferentes ángulos. Algunos de ellos están uno al lado del otro (o encima de él), por lo que conocer el desplazamiento no es suficiente para determinar con qué zona horaria está relacionada la hora.

¿Y qué pasa con UTC? Bueno, es la única cámara que garantiza un manejo firme. Está sobre un trípode, firmemente anclado al suelo. No irá a ninguna parte. A su ángulo de perspectiva lo llamamos desplazamiento cero.

Visualización de tiempo instantáneo versus tiempo calendario

Entonces, ¿qué nos dice esta analogía? Proporciona algunas pautas intuitivas.

  • Si estás representando el tiempo relativo a algún lugar en particular, represéntalo en tiempo calendario con un DateTime. Sólo asegúrese de no confundir nunca un calendario con otro. Unspecifieddebería ser tu suposición. Localsólo es útil viniendo de DateTime.Now. Por ejemplo, puedo obtenerlo DateTime.Nowy guardarlo en una base de datos, pero cuando lo recupero, debo asumir que es Unspecified. No puedo confiar en que mi calendario local sea el mismo calendario del que fue tomado originalmente.

  • Si siempre debes estar seguro del momento, asegúrate de representar el tiempo instantáneo. Úselo DateTimeOffsetpara aplicarlo o use UTC DateTimepor convención.

  • Si necesita realizar un seguimiento de un momento instantáneo, pero también desea saber "¿Qué hora pensó el usuario que era en su calendario local?" - entonces debes usar un DateTimeOffset. Esto es muy importante, por ejemplo, para los sistemas de cronometraje, tanto por motivos técnicos como legales.

  • Si alguna vez necesita modificar una grabación anterior DateTimeOffset, no tiene suficiente información solo en la compensación para garantizar que la nueva compensación siga siendo relevante para el usuario. También debe almacenar un identificador de zona horaria (piense: necesito el nombre de esa cámara para poder tomar una nueva fotografía incluso si la posición ha cambiado).

    También cabe señalar que Noda Time tiene una representación llamada ZonedDateTimepara esto, mientras que la biblioteca de clases base .Net no tiene nada similar. Necesitaría almacenar tanto a DateTimeOffsetcomo a TimeZoneInfo.Idvalor.

  • Ocasionalmente, querrás representar una hora del calendario que sea local para "quien la esté mirando". Por ejemplo, a la hora de definir lo que significa hoy . Hoy siempre es de medianoche a medianoche, pero estos representan un número casi infinito de rangos superpuestos en la línea de tiempo instantánea. (En la práctica, tenemos un número finito de zonas horarias, pero puede expresar las compensaciones hasta el último momento). Entonces, en estas situaciones, asegúrese de comprender cómo limitar el "¿quién pregunta?" preguntas a una única zona horaria, o tratar de traducirlas de nuevo a tiempo instantáneo, según corresponda.

Aquí hay algunos otros detalles DateTimeOffsetque respaldan esta analogía y algunos consejos para mantenerla clara:

  • Si compara dos DateTimeOffsetvalores, primero se normalizan a desplazamiento cero antes de comparar. En otras palabras, 2012-01-01T00:00:00+00:00y 2012-01-01T02:00:00+02:00se refieren al mismo momento instantáneo, y por tanto son equivalentes.

  • Si está realizando alguna prueba unitaria y necesita estar seguro del desplazamiento, pruebe tanto el DateTimeOffsetvalor como la .Offsetpropiedad por separado.

  • Hay una conversión implícita unidireccional integrada en el marco .Net que le permite pasar DateTimea cualquier DateTimeOffsetparámetro o variable. Al hacerlo, lo .Kindimportante . Si pasa un tipo UTC, se trasladará con un desplazamiento cero, pero si pasa .Localo .Unspecified, se asumirá que es local . Básicamente, el marco dice: "Bueno, me pediste que convirtiera el tiempo del calendario en tiempo instantáneo, pero no tengo idea de dónde vino esto, así que simplemente usaré el calendario local". Este es un gran problema si carga un no especificado DateTimeen una computadora con una zona horaria diferente. (En mi humilde opinión, eso debería generar una excepción, pero no es así).

Enchufe descarado:

Muchas personas me han dicho que encuentran esta analogía extremadamente valiosa, por lo que la incluí en mi curso Pluralsight, Fundamentos de fecha y hora . Encontrará un tutorial paso a paso de la analogía de la cámara en el segundo módulo, "El contexto importa", en el clip titulado "Calendar Time vs. Instantaneous Time".

Matt Johnson-Pint avatar Jan 10 '2013 22:01 Matt Johnson-Pint

De Microsoft:

Estos usos de los valores DateTimeOffset son mucho más comunes que los de los valores DateTime. Como resultado, DateTimeOffset debe considerarse el tipo de fecha y hora predeterminado para el desarrollo de aplicaciones.

fuente: "Elegir entre DateTime, DateTimeOffset, TimeSpan y TimeZoneInfo" , MSDN

Lo usamos DateTimeOffsetpara casi todo, ya que nuestra aplicación trata con momentos particulares en el tiempo (por ejemplo, cuando se creó/actualizó un registro). DATETIMEOFFSETComo nota al margen, también lo utilizamos en SQL Server 2008.

Lo veo DateTimeútil cuando quieres tratar solo con fechas, solo con horas o tratar cualquiera de las dos en un sentido genérico. Por ejemplo, si tiene una alarma que desea que suene todos los días a las 7 a. m., puede guardarla en un archivo DateTimeporque desea que suene a las 7 a. m. independientemente del horario de verano. Pero si desea representar el historial de ocurrencias de alarmas, usaría .DateTimeKindUnspecifiedDateTimeOffset

Tenga cuidado al utilizar una combinación de tipos DateTimeOffsety DateTimeespecialmente al asignarlos y compararlos. Además, solo compare DateTimeinstancias que sean iguales DateTimeKindporque DateTimeignora el desplazamiento de la zona horaria al comparar.

Clay avatar Jan 09 '2013 19:01 Clay

DateTime es capaz de almacenar sólo dos horas distintas, la hora local y UTC. La propiedad Kind indica cuál.

DateTimeOffset amplía esto al poder almacenar horas locales desde cualquier parte del mundo. También almacena el desplazamiento entre esa hora local y UTC. Tenga en cuenta que DateTime no puede hacer esto a menos que agregue un miembro adicional a su clase para almacenar ese desplazamiento UTC. O solo trabajar con UTC. Lo cual en sí mismo es una buena idea por cierto.

Hans Passant avatar Dec 02 '2010 17:12 Hans Passant

Este fragmento de código de Microsoft lo explica todo:

// Find difference between Date.Now and Date.UtcNow
  date1 = DateTime.Now;
  date2 = DateTime.UtcNow;
  difference = date1 - date2;
  Console.WriteLine("{0} - {1} = {2}", date1, date2, difference);

  // Find difference between Now and UtcNow using DateTimeOffset
  dateOffset1 = DateTimeOffset.Now;
  dateOffset2 = DateTimeOffset.UtcNow;
  difference = dateOffset1 - dateOffset2;
  Console.WriteLine("{0} - {1} = {2}", 
                    dateOffset1, dateOffset2, difference);
  // If run in the Pacific Standard time zone on 4/2/2007, the example
  // displays the following output to the console:
  //    4/2/2007 7:23:57 PM - 4/3/2007 2:23:57 AM = -07:00:00
  //    4/2/2007 7:23:57 PM -07:00 - 4/3/2007 2:23:57 AM +00:00 = 00:00:00
Mojtaba avatar Oct 19 '2018 09:10 Mojtaba