2009-05-07 17 views
28

Estoy trabajando en un proyecto de "sistema de recordatorio en línea" (ASP.NET 2.0 (C#)/SQL Server 2005)¿Cómo trabajar con husos horarios en ASP.NET?

Como este es un servicio de recordatorio que enviará el correo a los usuarios en una fecha determinada. Pero el problema es que los usuarios no son de un país específico, sino de todo el mundo y de diferentes zonas horarias. Ahora, cuando me estoy registrando, pido la zona horaria de los usuarios de la misma manera que Windows pregunta por nuestra zona horaria en el momento de la instalación.

Pero no obtengo el si el usuario ha seleccionado (+5.30) o algo así como la zona horaria y cómo manejar esta zona horaria en mi aplicación asp.net. Cómo trabajar de acuerdo a la zona horaria

¿Y sugerir si hay alguna forma mejor de manejar zonas horarias en esta aplicación?

Gracias

+0

Esta pregunta puede ser antigua y tener una respuesta aceptada, pero es bastante amplia y las respuestas solo abordan un aspecto del problema. La respuesta también es incorrecta, ya que la solución recomendada no cubre el horario de verano y utiliza 'TimeZoneInfo', que no estaba disponible en .NET 2.0 (que como requisito de esta pregunta). Recomiendo que esta pregunta sea cerrada o eliminada. –

Respuesta

27

Lo primero es asegurarse de que la zona horaria que sus datos están en. Yo recomendaría asegurándose de que cualquier DateTime que se almacenan, se almacena en la hora UTC (use el DateTime.ToUniversalTime() a apoderarse de él) .

Cuando vaya a almacenar un recordatorio para un usuario, necesitará la hora UTC actual, agregue o elimine la diferencia de zona horaria del usuario y convierta esa nueva hora a UTC; esto es lo que quiere almacenar en la base de datos.

Luego, cuando desee verificar el envío de recordatorios, simplemente debe buscar en la base de datos los avisos que se deben enviar ahora, según la hora UTC; esencialmente obtienes todos los recordatorios que tienen una marca de tiempo que está antes de DateTime.Now.ToUniversalTime().

actualización con algunos detalles de implementación: Usted puede obtener una lista de las zonas horarias del método TimeZoneInfo.GetSystemTimeZones(); puede usarlos para mostrar una lista de zonas horarias para el usuario. Si almacena la propiedad Id de la zona horaria seleccionada, puede crear una instancia de clase TimeZoneInfo de ella, y calcular la hora UTC para un valor de fecha/hora a partir de:

TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("<the time zone id>"); 
// May 7, 08:04:00 
DateTime userDateTime = new DateTime(2009, 5, 7, 8, 4, 0); 
DateTime utcDateTime = userDateTime.Subtract(tzi.BaseUtcOffset); 
+0

Ok, tu idea suena bien, pero estoy sintiendo un problema allí. Dijiste "necesitarás la hora UTC actual, agregar o eliminar la diferencia de huso horario del usuario y convertir esa nueva hora a UTC"; pero ahora cuando ejecutaré mi proceso que enviará los recordatorios. Estoy ubicado en la zona horaria india (IST), por lo tanto, ¿cuándo debo ejecutar los recordatorios para que el recordatorio se envíe a los usuarios en el momento correcto. – Prashant

+0

En lugar de almacenar en UTC, lo que pensé es: tendré tres columnas en mi tabla de recordatorio_schedule que serán "Original_DateTime", "UTC_DateTime" y "IST_DateTime". Ahora el tiempo de fecha Original_DateTime almacenará la fecha exacta que establecerá el usuario. UTC_DateTime almacenará el UTC DateTime en función de la zona horaria de los usuarios. y el último "IST_DateTime" almacenará la fecha y hora de acuerdo con la zona horaria india al convertir UTC_DateTime a Indian TimeZone. Finalmente, ejecutaré mis recordatorios enviando el proceso de acuerdo con INdian tmezone y, por lo tanto, todo recordatorio se enviará en el tiempo exacto. – Prashant

+0

No estoy seguro de que la idea que he dado arriba sea perfecta, pero estas son mis ideas, por favor díganme, ¿cómo debo continuar? – Prashant

0

Básicamente, todo lo que tiene que hacer es agregar el desplazamiento (horas + minutos) a la hora local que ingresó el usuario. Agregar el desplazamiento básicamente te da un DateTime en la zona horaria UTC (básicamente GMT).

Por lo general, lo más fácil es estandarizar todos sus tiempos en UTC, para que su lógica de aplicación no tenga que ocuparse de los desplazamientos.

Esta página tiene algunos buenos ejemplos: http://msdn.microsoft.com/en-us/library/bb546099.aspx

2

Es posible que desee buscar en el uso de la estructura DateTimeOffset en lugar del DateTime si está en marco 2.0 o posterior.

DateTimeOffset representa un punto en el tiempo relativo a la hora UTC, por lo que debería ser más fácil trabajar en este caso.

18

recomendaría a tiempo siempre uso UTC (GMT) en el lado del servidor (en el código subyacente, base de datos, etc), y convertir el tiempo de UTC a hora local para fines de visualización solamente. Esto significa que todas las manipulaciones de tiempo, incluido el ahorro de tiempo en la base de datos, la realización de cálculos, etc., deben realizarse con UTC.

El problema es: ¿cómo sabe el código subyacente cuál es la zona horaria del navegador del cliente? Supongamos que el usuario ingresa algún valor de fecha/hora (como 12/30/2009 14:30) en el formulario y lo envía al servidor. Suponiendo que el usuario envió la hora local, ¿cómo sabe el servidor cómo convertir este valor en UTC?

La aplicación puede solicitar al usuario que especifique la zona horaria (y la guarde en una cookie o base de datos persistente), pero requiere un esfuerzo adicional del usuario, y su aplicación debería implementar la lógica y pantallas para esto . Sería mejor si la aplicación pudiera determinar la zona horaria del cliente automáticamente.

He resuelto este problema con la ayuda de la función getTimezoneOffset de JavaScript, que es la única API que puede indicarle al servidor la diferencia horaria entre la hora local en el cliente y GMT. Como esta es una API del lado del cliente, hice lo siguiente: en el servidor, compruebe si hay una cookie de sesión personalizada que contenga el valor de compensación de tiempo, y si no está disponible, vuelva a cargar la página (solo durante las llamadas GET y no POST) con alguna lógica de JavaScript agregada para generar el desplazamiento de tiempo y guardarlo en la cookie. Desde el lado del cliente esto es casi transparente (una vez durante la sesión, recargo una página en GET). Una vez que tengo el desplazamiento en la cookie, lo aplico a las funciones de gestión del tiempo dependiendo de la dirección de la conversión de tiempo (UTC a la hora local, o hora local a UTC).

Esto puede sonar un poco complicado, y lo es, pero después de escribir funciones de ayuda, la integración de esta característica en el sitio era una cuestión de hacer una sola llamada en Load (de páginas que necesitan conversión de tiempo), y utilizando rutinas de conversión de tiempo al enviar y recuperar valores de tiempo hacia y desde el navegador. Aquí está un ejemplo de cómo se puede utilizar:

using My.Utilities.Web; 
... 

// Derive the form class from BaseForm instead of Page. 
public class WebForm1: BaseForm 
{ 
... 
private void Page_Load(object sender, System.EventArgs e) 
{ 
    // If we only want to load the page to generate the time 
    // zone offset cookie, we do not need to do anything else. 
    if (InitializeLocalTime()) 
    return; 

    // Assume that txtStartDate is a TextBox control. 
    if (!IsPostback) 
    { 
    // To display a date-time value, convert it from GMT (UTC) 
    // to local time. 
    DateTime startDate = GetStartDateFromDB(...); 
    txtStartDate.Text = FormatLocalDate(startDate); 
    ... 
    } 
    else 
    { 
    // To save a date-time value, convert it from local 
    // time to GMT (UTC). 
    DateTime tempDate = DateTime.Parse(txtStartDate.Text); 
    DateTime startDate = ConvertLocalTimeToUtc(tempDate); 
    SaveStartDateInDB(startDate, ...); 
    ... 
    } 
} 
... 
} 

Si necesita más detalles, consulte el artículo It’s About Time: Localizing Time in ASP.NET Applications (lo siento, pero no tengo un vínculo directo al artículo sobre el sitio del editor, ya que asp .netPRO restringe el acceso solo a los suscriptores pagos; sin embargo, hay enlaces a copias en PDF). Me gustaría poder publicar la muestra del artículo, pero no quiero violar los derechos de autor; sin embargo, aquí hay un project to build a helper library que tiene toda la funcionalidad y documentación necesarias (simplemente ignore las cosas que no necesita).

ACTUALIZACIÓN: El artículo ha sido publicado en línea con el proyecto de muestra publicado por el nuevo editor here.

+0

No estoy de acuerdo con la afirmación de que su aplicación debe determinar automáticamente la zona horaria del usuario. Los usuarios pueden establecer cualquier zona horaria/fecha/hora que deseen en su sistema operativo y omitir sus reglas comerciales. Nunca confíes en la entrada del usuario. – BrunoSalvino

+4

No entiendo tu punto Bruno. Primero, no hay reglas comerciales asociadas con las zonas horarias. Es un problema de usabilidad. Podríamos haber usado GMT, pero no es conveniente para los usuarios, así que usamos la hora local. Si el usuario cambia el reloj del sistema (o de cualquier forma que use para especificar la zona horaria), ¿a quién le importa? No veo un problema aquí. Tampoco estoy siguiendo una transición de su primera declaración a la segunda declaración. ¿No te gusta la parte "automática", o no te gusta la idea de utilizar la hora local en absoluto (si no se hace automáticamente, el usuario debe ser capaz de cambiarla de alguna manera, a la derecha)? –

+0

+1. @ BrunoSalvino, ¿cómo sugerirías pasar los datos de la zona horaria? La otra forma en que puedo pensar es haciendo una aportación explícita del usuario. Este último es aún menos confiable que la solución automática propuesta aquí, ya que es más probable que el usuario cometa un error. Desde la perspectiva del usuario, esto requerirá entradas en la zona horaria, que no es fácil de usar, especialmente cuando la página ni siquiera requiere información de fecha y hora, pero aún debe persistir la fecha y hora de determinada interacción del usuario (como el momento en que el usuario subió archivo o hizo una transacción financiera). –

3

El problema con todas las respuestas hasta el momento es que no tienen en cuenta lo que Prashant está tratando de lograr. Si el usuario de su sistema el día anterior al cambio de horario de verano tiene una compensación de +12 y establece un recordatorio para el día siguiente, su compensación cuando se supone que el recordatorio se activará será +13 en su lugar.

Es por eso que solo puede usar el desplazamiento actual para algo que está sucediendo ahora. Aunque estoy de acuerdo con todos los demás en que todas las veces el lado del servidor (excepto posiblemente los que se usan solo para la visualización) deben almacenarse en UTC.

0

El problema es que el desplazamiento del UTC variará en diferentes momentos del año; cada zona horaria tiene sus propias reglas. (Esto lo aprendí de la manera difícil cuando se desarrolla sala de reuniones aplicación de programación.)

parece que hay soporte integrado aquí: http://msdn.microsoft.com/en-us/library/system.timezoneinfo.converttime.aspx

no lo he probado a mí mismo, pero parece prometer la conversión correcta, lo que representa para el horario de verano

Si no, aquí es una herramienta (caro) comercial que he utilizado: http://www.worldtimeserver.com/time_zone_guide/

1

Hay 2 pasos:

  • detectar diferentes zona horaria en el lado del cliente usando Javascript:

    var dt = new Date(); 
    var diffInMinutes = -dt.getTimezoneOffset(); 
    
  • Luego, en el lado del servidor, código C# para convertir la hora del servidor a la hora del cliente en función de la compensación de zona horaria detectada anterior:

------------------------;

string queryStr = Request.QueryString["diffInMinutes"]; 
int diffInMinutes = 0; 
if (Int32.TryParse(queryStr, out diffInMinutes)) 
{ 
    clientTime = serverTime.ToUniversalTime().AddMinutes(diffInMinutes); 
} 
+0

Funciona para mí. Buen ejemplo. El problema no es almacenar la fecha como UTC ya que mostró que ya hay un método "ToUniveralTime()" para convertir a UTC si es necesario. El verdadero problema es obtener el desplazamiento de la zona horaria local donde se encuentra el cliente. Este ejemplo también funciona muy bien para MVC, donde los objetos json pasan al controlador. –