c# - hora - utc gmt
Cómo convertir el tiempo del servidor a la hora local y lidiar con el horario de verano (3)
Nunca debe confiar en la configuración de zona horaria de un servidor. Por lo tanto,
DateTime.Now
no se debe usar nunca en una aplicación ASP.NET.Hay muchas otras razones para evitar
DateTime.Now
. Leer: el caso contra DateTime.Now .La hora local del servidor nunca se garantiza que sea la hora local del usuario de su sitio web de todos modos. Si es así, es solo una coincidencia.
La forma más fácil de obtener la hora actual del usuario en su zona horaria es a través de JavaScript:
var now = new Date();
Aunque esto se basa en el reloj del usuario, que puede o no estar configurado correctamente. Para tener alguna garantía sobre el tiempo, tendría que usar la hora UTC del reloj del servidor, con la zona horaria del usuario aplicada.
Un enfoque que podría considerar es enviar la hora UTC del servidor al cliente, luego cargar eso en JavaScript en el cliente para proyectarlo a su zona horaria:
// C# string serverUtcTime = DateTime.UtcNow.ToString("o"); // "2015-09-18T17:53:15.6988370Z" // JS var now = new Date("2015-09-18T17:53:15.6988370Z");
En realidad, detectar el huso horario del usuario es un problema difícil que actualmente no tiene una solución. Algunos pueden recomendar una
new Date().getTimezoneOffset()
, pero eso solo le proporciona el desplazamiento numérico actual, no la zona horaria. Las compensaciones pueden cambiar para el horario de verano, y muchas zonas horarias utilizan compensaciones similares. También hay complicaciones para las fechas históricas cerca de las transiciones DST que funcionarán en su contra.Las secuencias de comandos como jsTimeZoneDetect pueden adivinar su ID de zona horaria IANA, como
America/New_York
para la hora del este, pero no son 100% precisas. Si necesita la zona horaria del usuario en su servidor, en última instancia debería preguntarle al usuario su zona horaria en algún lugar de su aplicación.En .NET, puede usar Noda Time para trabajar con zonas horarias de IANA. Sin Noda Time, .NET tiene la clase
TimeZoneInfo
, pero solo puede funcionar con zonas horarias de Windows.Si sabe con certeza que los usuarios se encuentran en Atlanta, GA (que se encuentra en la zona horaria del este de EE. UU.), Puede hacer esto:
DateTime utc = DateTime.UtcNow; TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); DateTime eastern = TimeZoneInfo.ConvertTimeFromUtc(utc, tz);
O bien, con las ID de zona horaria de Noda Time y IANA:
Instant now = SystemClock.Instance.Now; DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"]; ZonedDateTime eastern = now.InZone(tz);
Alojo mi sitio web (asp.net webforms, .Net 4.5, SQL Server 2012) en Godaddy y ellos (el servidor) usan Mountain Standard Time
( -7 en comparación con la hora UTC
) que nunca cambia y no observa el horario de verano.
Entonces si lo hago
Response.Write("UTC Time: " + DateTime.UtcNow.ToString() + "<br/>");
Response.Write("Server Time: " + DateTime.Now.ToString() + "<br/>");
Response.Write("Server DateTimeOffset: " + DateTimeOffset.Now.ToString() + "<br/>");
Mostrará esto:
UTC Time: 9/18/2015 5:14:09 PM
Server Time: 9/18/2015 10:14:09 AM
Server DateTimeOffset: 9/18/2015 10:14:09 AM -07:00
Pero mis usuarios están ubicados en Atlanta, GA, que observa el horario de verano y según timeanddate.com usan EDT en verano y EST en invierno
¿Cómo obtengo la hora actual correcta del usuario? Digamos que el usuario abre mi aplicación web y pulsa el botón Show my time
, ¿mostrará la hora correcta del usuario actual?
Echale un vistazo a éste ejemplo. Esto es bastante fácil.
[Test, TestCase(1), TestCase(9)]
public void Test(int month)
{
var serverTime = new DateTime(2015, month, 18, 10, 14, 09);
// No Daylight saving in Russia
var serverTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
// Daylight saving in Atlanta
var localTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Atlantic Standard Time");
// check if ConvertTime take care of daylight saving
var localTime = TimeZoneInfo.ConvertTime(serverTime, serverTimeZone, localTimeZone);
// it does
if (localTimeZone.IsDaylightSavingTime(localTime))
Assert.AreEqual(string.Format("{0}/18/15 04:14 AM", month), localTime.ToString("M/dd/yy hh:mm tt", System.Globalization.CultureInfo.InvariantCulture));
else
Assert.AreEqual(string.Format("{0}/18/15 03:14 AM", month), localTime.ToString("M/dd/yy hh:mm tt", System.Globalization.CultureInfo.InvariantCulture));
}
Puede usar TimeZoneInfo.ConvertTime para convertir de una zona horaria a otra. Sin embargo, si simplemente convierte a EST o EDT, siempre mostrará ese valor. Si desea mostrar siempre la hora correcta para el cliente, deberá hacer algo como usar Javascript para almacenar la zona horaria local del navegador del cliente en una cookie, luego use ese valor como la zona horaria a la que desea convertir.
Puede ser un poco más simplificado obtener UtcTime del servidor y convertirlo con TimeZoneInfo.ConvertTimeFromUtc, si espera hacer gran parte de esto. Básicamente el mismo proceso, sin embargo.