DateTimeOffset
es una representación del tiempo instantáneo (también conocido como tiempo absoluto ). Con eso, me refiero a un momento en el tiempo que es universal para todos (sin tener en cuenta los segundos bisiestos o los efectos relativistas de la dilatación del tiempo ). Otra forma de representar el tiempo instantáneo es con un lugar DateTime
donde .Kind
está DateTimeKind.Utc
.
Esto es distinto del tiempo de calendario (también conocido como tiempo civil ), que es una posición en el calendario de alguien, y hay muchos calendarios diferentes en todo el mundo. Llamamos a estos calendarios zonas horarias . El tiempo del calendario está representado por un lugar DateTime
donde .Kind
está DateTimeKind.Unspecified
, o DateTimeKind.Local
. Y .Local
solo es significativo en escenarios en los que tiene una comprensión implícita de dónde está posicionada la computadora que está utilizando el resultado. (Por ejemplo, la estación de trabajo de un usuario)
Entonces, ¿por qué en DateTimeOffset
lugar de un UTC DateTime
? Se trata de perspectiva. Usemos una analogía: fingiremos ser fotógrafos.
Imagine que está parado en una línea de tiempo del calendario, apuntando con una cámara a una persona en la línea de tiempo instantánea que se encuentra frente a usted. Alinee 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 una mano firme, por lo que tu cámara está temblorosa).
La persona de pie en la foto vería el ángulo desde el cual proviene su cámara. Si otros tomaran fotos, podrían ser desde diferentes ángulos. Esto es lo que representa la Offset
parte de DateTimeOffset
.
Por lo tanto, si etiqueta su cámara como "Hora del Este", a veces apunta desde -5 y otras desde -4. Hay cámaras en todo el mundo, todas etiquetadas como 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 uno encima del otro), por lo que conocer el desplazamiento no es suficiente para determinar con qué zona horaria está relacionada la hora.
¿Y qué hay de UTC? Bueno, es la única cámara que garantiza tener una mano firme. Está en un trípode, firmemente anclado en el suelo. No va a ninguna parte. Llamamos a su ángulo de perspectiva el desplazamiento cero.
Entonces, ¿qué nos dice esta analogía? Proporciona algunas pautas intuitivas.
Si está representando el tiempo en relación con algún lugar en particular, hágalo en tiempo calendario con a DateTime
. Solo asegúrese de no confundir nunca un calendario con otro. Unspecified
Debería ser su suposición. Local
solo es útil viniendo de DateTime.Now
. Por ejemplo, podría obtenerlo DateTime.Now
y guardarlo en una base de datos, pero cuando lo recupere, debo asumir que es así Unspecified
. No puedo confiar en que mi calendario local sea el mismo calendario del que fue tomado originalmente.
Si siempre debe estar seguro del momento, asegúrese de representar el tiempo instantáneo. Úselo DateTimeOffset
para aplicarlo, o use UTC DateTime
por convención.
Si necesita realizar un seguimiento de un momento de tiempo instantáneo, pero también desea saber "¿A qué hora pensó el usuario que estaba en su calendario local?" - entonces debes usar a DateTimeOffset
. Esto es muy importante para los sistemas de cronometraje, por ejemplo, tanto por cuestiones técnicas como legales.
Si alguna vez necesita modificar un registro anterior DateTimeOffset
, no tiene suficiente información solo en el desplazamiento para garantizar que el nuevo desplazamiento aún sea relevante para el usuario. Debe también almacenar un identificador de zona horaria (piensa - Necesito el nombre de esa cámara para que pueda tomar una nueva imagen, incluso si la posición ha cambiado).
También debe señalarse que Noda Time tiene una representación llamada ZonedDateTime
para esto, mientras que la biblioteca de clase base .Net no tiene nada similar. Tendría que almacenar tanto un DateTimeOffset
como un TimeZoneInfo.Id
valor.
Ocasionalmente, querrá representar un tiempo de calendario que sea local para "quien lo esté mirando". Por ejemplo, al 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 la marca). En estas situaciones, asegúrese de comprender cómo limitar el "¿quién pregunta?" pregunta a una sola zona horaria, o trata de traducirlos nuevamente al tiempo instantáneo según corresponda.
Aquí hay algunos otros pequeños detalles sobre DateTimeOffset
eso que respaldan esta analogía, y algunos consejos para mantenerla recta:
Si compara dos DateTimeOffset
valores, primero se normalizan a cero antes de comparar. En otras palabras, 2012-01-01T00:00:00+00:00
y se 2012-01-01T02:00:00+02:00
refieren al mismo momento instantáneo, y por lo tanto son equivalentes.
Si está haciendo alguna prueba unitaria y necesita asegurarse del desplazamiento, pruebe tanto el DateTimeOffset
valor como la .Offset
propiedad por separado.
Hay una conversión implícita unidireccional integrada en el marco .Net que le permite pasar DateTime
a cualquier DateTimeOffset
parámetro o variable. Al hacerlo, los .Kind
asuntos . Si pasa un tipo GMT, llevará con un desplazamiento cero, pero si pasa o bien .Local
o .Unspecified
, asumirá ser locales . El marco básicamente dice: "Bueno, me pediste que convirtiera el tiempo del calendario a tiempo instantáneo, pero no tengo idea de dónde vino esto, así que solo voy a usar el calendario local". Este es un gran problema si carga un no especificado DateTime
en una computadora con una zona horaria diferente. (En mi humilde opinión, eso debería arrojar una excepción, pero no lo hace).
Enchufe desvergonzado:
Muchas personas han compartido conmigo 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, "Context Matters", en el clip titulado "Calendar Time vs. Instant Time".