DateTime.Now vs. DateTime.UtcNow

225

Me he estado preguntando cuáles son exactamente los principios de cómo funcionan las dos propiedades. Sé que el segundo es universal y básicamente no trata con zonas horarias, pero ¿alguien puede explicar en detalle cómo funcionan y cuál debería usarse en qué escenario?

Slavo
fuente
1
puede ser demasiado tarde pero quiero señalar este blog: blog.angeloflogic.com/2013/10/…
Kai Wang
pequeñas cotas de referencia rextester.com/QRDR82396
Daniel B

Respuestas:

346

DateTime.UtcNow le informa la fecha y la hora como sería en la hora universal coordinada, que también se llama zona horaria de la hora media de Greenwich, básicamente como sería si estuviera en Londres, Inglaterra, pero no durante el verano. DateTime.Now proporciona la fecha y la hora como le parecería a alguien en su localidad actual.

Recomiendo usar DateTime.Nowcada vez que le muestres una fecha a un ser humano, de esa manera se sienten cómodos con el valor que ven, es algo que pueden comparar fácilmente con lo que ven en su reloj o reloj. Úselo DateTime.UtcNowcuando desee almacenar fechas o úselos para cálculos posteriores de esa manera (en un modelo cliente-servidor) sus cálculos no se confunden con clientes en diferentes zonas horarias de su servidor o entre sí.

Blair Conrad
fuente
84
Un punto excelente: al almacenar fechas en una base de datos o archivo, ¡definitivamente almacénelas en UTC!
Jeff Atwood
15
Debe tener en cuenta que cuando desea almacenar fechas en UTC en la base de datos, debe asegurarse de que la base de datos no agregue su propia zona horaria a las fechas que no dan zonas horarias explícitas. Tenga en cuenta que DateTime siempre usará la zona horaria actual cuando se le solicite una.
Omer van Kloeten
@OmervanKloeten da un muy buen punto. Me pregunto si hay una solución elegante 'completa' para esto, para almacenar y recibir las fechas correctamente cada vez, incluso si su servidor IIS y SQL están en diferentes zonas horarias.
TheGeekZn
1
@ JoshYates1980 Sí, solo debes hacer DateTime.UtcNow.AddYears (1)
CathalMF
3
Use NodaTime : lo obligará a pensar en el tiempo de una manera más útil y
evitará
86

Es realmente bastante simple, así que creo que depende de cuál sea tu audiencia y dónde vivan.

Si no usa Utc, debe conocer la zona horaria de la persona a la que le está mostrando las fechas y horas; de lo contrario, le dirá que algo sucedió a las 3 p.m. en la hora del sistema o del servidor, cuando realmente sucedió a las 5 p.m. ellos pasan a vivir.

Usamos DateTime.UtcNowporque tenemos una audiencia web global y porque preferiría no molestar a todos los usuarios para que llenen un formulario que indique en qué zona horaria viven.

También mostramos tiempos relativos (hace 2 horas, hace 1 día, etc.) hasta que la publicación envejezca lo suficiente como para que la hora sea "la misma" sin importar en qué lugar de la Tierra viva.

Jeff Atwood
fuente
También quiero en segundo lugar que almacenar DateTime.UtcNow solo sea necesario cuando se realizan cálculos con 2 fechas para obtener las horas correctas. Cuando solo tengo que mostrar una Fecha de registro en Fecha y hora. Ahora es suficiente.
Elisabeth
36

También tenga en cuenta la diferencia de rendimiento; DateTime.UtcNowes alrededor de 30 veces más rápido DateTime.Now, porque internamente DateTime.Nowestá haciendo muchos ajustes de zona horaria (puede verificarlo fácilmente con Reflector).

Por lo tanto, NO lo use DateTime.Nowpara mediciones de tiempo relativo.

Magnus Krisell
fuente
Me ha llevado un viaje doloroso saber que UtcNow tiene un mejor rendimiento y que simplemente guardar sus fechas en mysql y suponer que es utc y comparar las pantallas dependientes de la fecha con UtcNow simplifica estos problemas de zona horaria global
Diin
29

Un concepto principal de entender en .NET es que ahora es ahora por toda la tierra, no importa qué zona horaria está en Así que si se carga una variable con. DateTime.NowO DateTime.UtcNow-. La asignación es idéntica * Su DateTimeobjeto sabe qué zona horaria se encuentra en y toma eso en cuenta independientemente de la asignación.

La utilidad de DateTime.UtcNowes útil al calcular fechas a través de los límites del horario de verano. Es decir, en lugares que participan en el horario de verano, a veces hay 25 horas desde el mediodía hasta el mediodía del día siguiente, y a veces hay 23 horas entre el mediodía y el mediodía del día siguiente. Si desea determinar correctamente el número de horas desde el tiempo A y el tiempo B, primero debe traducir cada uno a sus equivalentes UTC antes de calcular el TimeSpan.

Esto está cubierto por una publicación de blog que escribí que explica más detalladamente TimeSpane incluye un enlace a un artículo de MS aún más extenso sobre el tema.

* Aclaración: cualquiera de las asignaciones almacenará la hora actual. Si tuviera que cargar dos variables, una vía DateTime.Now()y la otra vía, DateTime.UtcNow()la TimeSpandiferencia entre las dos sería milisegundos, no horas, suponiendo que se encuentre en una zona horaria a horas de GMT. Como se indica a continuación, la impresión de sus Stringvalores mostrará diferentes cadenas.

Carl Camera
fuente
1
Con respecto a "cargar una variable con DateTime.Now o DateTime.UtcNow - la asignación es idéntica": ¿Es posible que esto deba aclararse? Mientras me siento aquí en la zona horaria EDT (UTC -4), asigné dos variables a DateTime.UtcNow y DateTime.Now respectivamente, y luego imprimí sus valores con ToString (). Los valores mostrados estaban separados por 4 horas, no "idénticos".
Jon Schneider
2
@ JonSchneider, creo que tienes razón. La afirmación: "la asignación es idéntica" no es cierta. ToString () probablemente no sea la mejor manera de probar eso, porque podría mostrar fechas iguales de manera diferente (como lo hace Java). Las funciones de comparación son una mejor prueba y muestran que, de hecho, no son iguales.
Ted Bigham
Aclaración a mi declaración "idéntica": Cargue una variable a través de DateTime.Now y otra con DateTime.UtcNow y luego imprima la diferencia TimeSpan. La diferencia será milisegundos y no horas, suponiendo que esté a horas de GMT.
Carl Camera
18

Esta es una buena pregunta. Lo estoy reviviendo para dar un poco más de detalle sobre cómo .Net se comporta con diferentes Kindvalores. Como señala @ Jan Zich, en realidad es una propiedad de importancia crítica y se establece de manera diferente dependiendo de si se usa Nowo no UtcNow.

Internamente, la fecha se almacena como Ticksque (al contrario de la respuesta de @Carl Camera) es diferente dependiendo de si usa Nowo UtcNow.

DateTime.UtcNowse comporta como otros idiomas. Se establece Ticksen un valor basado en GMT. También se establece Kinden Utc.

DateTime.Nowaltera el Ticksvalor de lo que sería si fuera su hora del día en la zona horaria GMT . También se establece Kinden Local.

Si tiene 6 horas de retraso (GMT-6), obtendrá el tiempo GMT de hace 6 horas. .Net en realidad ignora Kindy trata esta vez como si fuera hace 6 horas, a pesar de que se supone que es "ahora". Esto se rompe aún más si crea una DateTimeinstancia, luego cambia su zona horaria e intenta usarla.

Las instancias de DateTime con diferentes valores 'Kind' NO son compatibles.

Veamos un código ...

    DateTime utc = DateTime.UtcNow;
    DateTime now = DateTime.Now;
    Debug.Log (utc + " " + utc.Kind);  // 05/20/2015 17:19:27 Utc
    Debug.Log (now + " " + now.Kind);  // 05/20/2015 10:19:27 Local

    Debug.Log (utc.Ticks);  // 635677391678617830
    Debug.Log (now.Ticks);  // 635677139678617840

    now = now.AddHours(1);
    TimeSpan diff = utc - now;
    Debug.Log (diff);  // 05:59:59.9999990

    Debug.Log (utc <  now);  // false
    Debug.Log (utc == now);  // false
    Debug.Log (utc >  now);  // true

    Debug.Log (utc.ToUniversalTime() <  now.ToUniversalTime());  // true
    Debug.Log (utc.ToUniversalTime() == now.ToUniversalTime());  // false
    Debug.Log (utc.ToUniversalTime() >  now.ToUniversalTime());  // false
    Debug.Log (utc.ToUniversalTime() -  now.ToUniversalTime());  // -01:00:00.0000010

Como puede ver aquí, las comparaciones y las funciones matemáticas no se convierten automáticamente a tiempos compatibles. El Timespandebería haber sido casi una hora, pero en cambio era casi 6. "utc <ahora" debería haber sido cierto (incluso agregué una hora para estar seguro), pero aún así era falso.

También puede ver el 'trabajo' que consiste simplemente en convertir al tiempo universal en cualquier lugar que Kindno sea el mismo.

Mi respuesta directa a la pregunta está de acuerdo con la recomendación de la respuesta aceptada sobre cuándo usar cada una. Siempre debe intentar trabajar con DateTimeobjetos que lo tengan Kind=Utc, excepto durante la E / S (visualización y análisis). Esto significa que casi siempre debería usarlo DateTime.UtcNow, excepto en los casos en que está creando el objeto solo para mostrarlo y descartarlo de inmediato.

Ted Bigham
fuente
7

DateTime no tiene idea de qué zonas horarias son. Siempre supone que estás en tu hora local. UtcNow solo significa "Restar mi zona horaria de la hora".

Si desea usar fechas que reconocen la zona horaria, use DateTimeOffset , que representa una fecha / hora con una zona horaria. Tenía que aprender eso por las malas.

Omer van Kloeten
fuente
99
Para ser completamente preciso (y evitar que la gente use Now sobre UtcNow por razones de rendimiento), es al revés: ahora agrega la zona horaria a UtcNow y, de hecho, es una magnitud más lenta.
mafu
5

La respuesta "simple" a la pregunta es:

DateTime.Now devuelve un valor DateTime que representa la hora actual del sistema (en cualquier zona horaria en la que se esté ejecutando el sistema). La propiedad DateTime.Kind será DateTimeKind.Local

DateTime.UtcNow devuelve un valor DateTime que representa la hora universal coordinada actual (también conocida como UTC), que será la misma independientemente de la zona horaria del sistema. La propiedad DateTime.Kind será DateTimeKind.Utc

PapillonUK
fuente
4

Solo una pequeña adición a los puntos mencionados anteriormente: la estructura DateTime también contiene un campo poco conocido llamado Kind (al menos, no lo supe durante mucho tiempo). Básicamente es solo una bandera que indica si la hora es local o UTC; no especifica el desplazamiento real desde UTC para las horas locales. Además del hecho de que indica con qué intenciones se construyó el estudio, también influye en la forma en que funcionan los métodos ToUniversalTime () y ToLocalTime () .

Jan Zich
fuente
1

DateTime.UtcNow es una escala de tiempo continua de un solo valor, mientras que DateTime.Now no es continua ni de un solo valor. La razón principal es el horario de verano, que no se aplica a UTC. Por lo tanto, UTC nunca salta hacia adelante o hacia atrás una hora, mientras que la hora local (DateTime.Now) sí. Y cuando salta hacia atrás, el mismo valor de tiempo ocurre dos veces.

usuario1315023
fuente
1

DateTime.UtcNow es una escala de tiempo universal que omite el horario de verano. Por lo tanto, UTC nunca cambia debido al horario de verano.

Pero, DateTime.Now no es continuo o de un solo valor porque cambia según el horario de verano. Lo que significa DateTime. Ahora, el mismo valor de tiempo puede ocurrir dos veces dejando a los clientes en un estado confuso.

ChaiVan
fuente
0

Cuando necesite una hora local para la máquina en la que se ejecuta su aplicación (como CEST para Europa), use Now. Si quieres un tiempo universal, UtcNow. Es solo cuestión de sus preferencias, probablemente crear un sitio web local / aplicación independiente que le gustaría usar el tiempo que el usuario tiene, tan afectado por su configuración de zona horaria: DateTime.Now.

Solo recuerde, para un sitio web es la configuración de zona horaria del servidor. Entonces, si está mostrando la hora para el usuario, obtenga su zona horaria preferida y cambie la hora (solo guarde el tiempo Utc en la base de datos y modifíquelo) o especifique que es UTC. Si olvida hacerlo, el usuario puede ver algo como: publicado hace 3 minutos y luego en un futuro cercano :)

kender
fuente
0

La gran diferencia :) es que DateTime.Now no es compatible con SharePoint Workflow, debe usar DateTime.UtcNow

Michel LAPLANE
fuente