zona horaria cambiar c# asp.net datetime timezone nodatime

c# - cambiar - DateTime.Now y cultura/zona horaria específica



datetime zona horaria c# (5)

El enfoque estándar es almacenar siempre los datos de tiempo como UTC si un momento particular en el tiempo es importante. Ese tiempo no se ve afectado por los cambios de zona horaria y las culturas.

El método más común para mostrar la hora con la zona horaria es almacenar la hora como UTC y convertirla en la combinación de cultura / zona horaria del usuario actual cuando se muestra el valor. Este enfoque solo requiere una fecha única de tiempo archivada en el almacenamiento.

Tenga en cuenta que para los casos web (como ASP.Net) es posible que primero deba averiguar la cultura / zona horaria del usuario y enviarla al servidor (ya que esta información no es necesaria en las solicitudes GET) o realizar el formateo de la hora en el navegador.

Dependiendo de lo que "muestre el mismo tiempo de historial" es posible que necesite almacenar información adicional como la cultura actual y / o la compensación actual. Si necesita mostrar el tiempo exactamente como lo vio el usuario original, también puede guardar la representación de la cadena (ya que los formatos / traducciones pueden cambiar más adelante y el valor será diferente, también es poco común).

Nota: la cultura y la zona horaria no están vinculadas entre sí, por lo que deberá decidir cómo debe manejar los casos como la cultura IN-IN en la zona horaria del PST de EE. UU.

Nuestra aplicación fue diseñada para manejar usuarios de diferentes ubicaciones geográficas.

No podemos detectar cuál es la hora local actual del usuario final y la zona horaria que opera en él. Seleccionan diferentes culturas como sv-se, en-us, ta-In incluso a las que acceden desde Europa / zona horaria de Londres ..

Lo alojamos en un servidor de hosting en EE. UU., Los usuarios de la aplicación son de Norway/Denmark/Sweden/UK/USA/India

El problema es que usamos DateTime.Now almacenamos el registro creado / fecha actualizada, etc.

Dado que el servidor se ejecuta en EE. UU., Todos los datos del usuario se guardan como hora de EE. UU .: (

Después de investigar en SO, decidimos almacenar todas las fechas del historial en DB como DateTime.UtcNow

PROBLEMA:

Hay un registro creado el 29 Dec 2013, 3:15 PM Swedish time .

public ActionResult Save(BookingViewModel model) { Booking booking = new Booking(); booking.BookingDateTime = model.BookingDateTime; //10 Jan 2014 2:00 P.M booking.Name = model.Name; booking.CurrentUserId = (User)Session["currentUser"].UserId; //USA Server runs in Pacific Time Zone, UTC-08:00 booking.CreatedDateTime = DateTime.UtcNow; //29 Dec 2013, 6:15 A.M BookingRepository.Save(booking); return View("Index"); }

Queremos mostrar el mismo tiempo de historial al usuario que inició sesión en India / Suecia / EE. UU.

A partir de ahora, estamos utilizando el usuario de cultura actual conectado y elegimos la zona horaria de un archivo de configuración y la utilizamos para la conversión con la clase TimeZoneInfo

<appSettings> <add key="sv-se" value="W. Europe Standard Time" /> <add key="ta-IN" value="India Standard Time" /> </appSettings> private DateTime ConvertUTCBasedOnCuture(DateTime utcTime) { //utcTime is 29 Dec 2013, 6:15 A.M string TimezoneId = System.Configuration.ConfigurationManager.AppSettings [System.Threading.Thread.CurrentThread.CurrentCulture.Name]; // if the user changes culture from sv-se to ta-IN, different date is shown TimeZoneInfo tZone = TimeZoneInfo.FindSystemTimeZoneById(TimezoneId); return TimeZoneInfo.ConvertTimeFromUtc(utcTime, tZone); } public ActionResult ViewHistory() { List<Booking> bookings = new List<Booking>(); bookings=BookingRepository.GetBookingHistory(); List<BookingViewModel> viewModel = new List<BookingViewModel>(); foreach (Booking b in bookings) { BookingViewModel model = new BookingViewModel(); model.CreatedTime = ConvertUTCBasedOnCuture(b.CreatedDateTime); viewModel.Add(model); } return View(viewModel); }

Ver código

@Model.CreatedTime.ToString("dd-MMM-yyyy - HH'':''mm")

NOTA: El usuario puede cambiar la cultura / idioma antes de iniciar sesión. Es una aplicación basada en localización, que se ejecuta en un servidor de los Estados Unidos.

He visto NODATIME , pero no pude entender cómo puede ayudar con una aplicación web multicultural alojada en una ubicación diferente.

Pregunta

¿Cómo puedo mostrar la misma fecha de creación del registro 29 Dec 2013, 3:15 PM para los usuarios registrados en INDIA / USA / Anywhere`?

A partir de ahora mi lógica en ConvertUTCBasedOnCuture se basa en el usuario registrado en cultura. Esto debería ser independientemente de la cultura, ya que el usuario puede iniciar sesión con cualquier cultura de India / EE. UU.

COLUMNA DE BASES DE DATOS

CreatedTime: SMALLDATETIME

ACTUALIZACIÓN: SOLUCIÓN INTENTADA:

DATABASE COLUMN TYPE: DATETIMEOFFSET

UI

Finalmente, estoy enviando la hora local del usuario actual utilizando el siguiente código de Momento.js en cada solicitud

$.ajaxSetup({ beforeSend: function (jqXHR, settings) { try { //moment.format gives current user date like 2014-01-04T18:27:59+01:00 jqXHR.setRequestHeader(''BrowserLocalTime'', moment().format()); } catch (e) { } } });

SOLICITUD

public static DateTimeOffset GetCurrentUserLocalTime() { try { return DateTimeOffset.Parse(HttpContext.Current.Request.Headers["BrowserLocalTime"]); } catch { return DateTimeOffset.Now; } }

entonces llamado

model.AddedDateTime = WebAppHelper.GetCurrentUserLocalTime();

En vista

@Model.AddedDateTime.Value.LocalDateTime.ToString("dd-MMM-yyyy - HH'':''mm")

A la vista muestra la hora local para el usuario, sin embargo, quiero ver como dd-MMM-yyyy CET/PST (hace 2 horas).

Esto hace 2 horas debería calcular a partir de la hora local del usuario final. Exactamente igual a la pregunta de desbordamiento de pila creada / editada, con visualización de zona horaria y cálculo de usuario local.

Ejemplo: answered Jan 25 ''13 at 17:49 CST (6 hours/days/month ago) Por lo tanto, el otro usuario de USA / INDIA puede entender realmente que este registro se creó exactamente 6 horas desde la hora actual de INDIA / USA

Casi creo que lo logré todo, excepto el formato de visualización y el cálculo. ¿Cómo puedo hacer esto?


Estoy un poco confundido por la redacción de su pregunta, pero parece que le gustaría determinar la zona horaria de su usuario.

  • ¿Has intentado preguntarles ? Muchas aplicaciones hacen que el usuario elija su zona horaria en la configuración del usuario.

  • Puede elegir de una lista desplegable o de un par de listas (país, luego zona horaria dentro del país), o de un control de selección de zona horaria basado en mapa .

  • Puede hacer una conjetura y usarlo como predeterminado a menos que su usuario lo cambie.

Si recorres esa ruta, deberás poder usar las zonas horarias de IANA / Olson, que es donde Noda Time entra en juego. Puede acceder a ellos desde DateTimeZoneProviders.Tzdb .

La ubicación de alojamiento es irrelevante si está utilizando UTC. Eso es bueno.

Además, si está utilizando Noda Time, entonces probablemente debería usar SystemClock.Instance.Now lugar de DateTime.UtcNow .

Véase también here y here .

Además, una solución alternativa sería simplemente pasar la hora UTC al navegador y cargarla en un objeto Date JavaScript. El navegador puede convertir eso a la hora local del usuario. También puedes usar una biblioteca como moment.js para hacer esto más fácil.

Actualizar

Con respecto a su enfoque de mapeo de códigos de cultura a zonas horarias:

<appSettings> <add key="sv-se" value="W. Europe Standard Time" /> <add key="ta-IN" value="India Standard Time" /> </appSettings>

Eso no funcionará , por varias razones:

  • Muchas personas usan una configuración cultural diferente en su computadora que el área en la que están físicamente. Por ejemplo, podría ser un hablante de inglés de los EE. UU. Que vive en Alemania, es probable que mi código de cultura aún sea en-US . en-US , No de-DE .

  • Un código de cultura que contiene un país se utiliza para distinguir los dialectos de un idioma. Cuando ves es-MX , significa "español, tal como se habla en México". No significa que el usuario esté realmente en México. Simplemente significa que el usuario habla ese dialecto del español, en comparación con es-ES que significa "español, tal como se habla en España".

  • Incluso si la parte del código de cultura del país podría ser confiable, ¡hay muchos países que tienen múltiples zonas horarias! Por ejemplo, ¿qué pondría en su lista de mapeo para en-US ? No puedes asumir que todos estamos en la Hora Estándar del Este.

Ahora, he explicado por qué su enfoque actual no funciona, le sugiero encarecidamente que acepte mi consejo original. Muy simple:

  1. Determine la zona horaria del usuario, preferiblemente preguntando, quizás con alguna ayuda de una de las utilidades a las que he vinculado anteriormente.

  2. Estás almacenando UTC, así que simplemente conviértelo a esa zona horaria para mostrarlo.

    Usando las zonas horarias de Microsoft

    TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time"); DateTime localDatetime = TimeZoneInfo.ConvertTimeFromUtc(yourUTCDateTime, tz); Usando las zonas horarias de IANA y la hora de Noda

    DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Stockholm"]; Instant theInstant = Instant.FromDateTimeUtc(yourUTCDateTime); LocalDateTime localDateTime = theInstant.InZone(tz);


Nos enfrentamos a un problema similar con una aplicación en la que trabajé recientemente. Durante el desarrollo, cada uno estaba en la misma zona horaria y el problema no se notó. Y, en cualquier caso, había muchos códigos heredados que habrían sido difíciles de cambiar, por no mencionar la conversión de toda la información de fecha y hora que ya estaba en la base de datos. Así que cambiar a DateTimeOffset no era una opción. Pero conseguimos que todo fuera coherente convirtiendo de la hora del servidor a la hora de salida del usuario y convirtiendo de la hora del usuario a la hora del servidor de entrada. También era importante hacer esto con cualquier comparación de fecha y hora que fuera un límite. Entonces, si un usuario esperaba que algo expirara a la medianoche de su tiempo, convertiríamos ese tiempo a la hora del servidor y haríamos todas las comparaciones en la hora del servidor. Esto parece mucho trabajo, pero fue mucho menos trabajo que la conversión de toda la aplicación y la base de datos para usar DateTimeOffsets.

Hear es un hilo que parece tener algunas buenas soluciones para el problema de la zona horaria.

Determinar la zona horaria de un usuario


Parece que necesita almacenar un DateTimeOffset lugar de un DateTime . Puede simplemente almacenar el DateTime local para el usuario que crea el valor, pero eso significa que no puede realizar ninguna operación de pedido, etc. No puede simplemente usar DateTime.UtcNow , ya que no almacenará nada para indicar la fecha local / hora del usuario cuando se creó el registro.

Alternativamente, puede almacenar un instante a tiempo junto con la zona horaria del usuario; eso es más difícil de lograr, pero le daría más información, ya que entonces podría decir cosas como "¿Cuál es la hora local del usuario una hora después?"

El alojamiento del servidor debe ser irrelevante: nunca debe utilizar la zona horaria del servidor. Sin embargo, deberá conocer el desplazamiento UTC apropiado (o zona horaria) para el usuario. Esto no se puede hacer solo en función de la cultura: deseará utilizar Javascript en la máquina del usuario para determinar el desplazamiento UTC en el momento en que esté interesado (no necesariamente "ahora").

Una vez que haya aprendido cómo almacenar el valor, recuperarlo es simple: si ya ha almacenado el instante UTC y un desplazamiento, simplemente aplique ese desplazamiento y volverá a la hora local del usuario original. No ha dicho cómo está convirtiendo los valores en texto, pero solo debe omitirlos, simplemente formatee el valor y obtenga la hora local original.

Si decides usar Noda Time, solo OffsetDateTime lugar de DateTimeOffset .


Si desea mostrar el historial de fecha / hora coherente al usuario, independientemente de la configuración regional desde la que está viendo el historial, entonces:

  1. Durante Save , almacene no solo la fecha / hora de "creación" de UTC, sino también la configuración regional detectada
  2. Utilice el almacenamiento saved from locale para calcular la fecha / hora original y emita una cadena para mostrar (es decir, no utilice la configuración regional actual del usuario cuando la muestra)

Si no tiene la capacidad de modificar su almacenamiento, entonces quizás pueda cambiar su envío para enviar la "hora actual del cliente", almacenarlo literalmente (no convertir a UTC) y luego mostrarlo literalmente (no convertir a cultura detectada) )

Pero como digo en mi comentario bajo su pregunta, no estoy seguro de haber cumplido con sus requisitos correctamente.