¿Cómo guardar correctamente DateTime usando Entity Framework Core?
Tengo una clase que contiene una propiedad DateTime. ¿Cómo ahorrar tiempo correctamente usando Entity Framework Core? Daré un ejemplo a continuación.
Utilizo el formato TIMESTAMP para almacenar el DateTime en la base de datos. Tengo un servidor y una base de datos (MySQL) que tienen la zona horaria +3 (Moscú).
SELECT TIMEDIFF(current_timestamp(), utc_timestamp()); // result = 03:00:00
También tengo un programa que se puede ejecutar en la PC de varios usuarios. El programa guarda el objeto que contiene la propiedad DateTime en la base de datos:
obj.DateTime = DateTime.Parse("2020-10-13T19:00:00+0300");
Ahora veamos algunas situaciones:
El programa se inicia en una PC con una zona horaria de +3 (Moscú)
Console.WriteLine (obj.DateTime? .ToString ()); // 2020-10-13 19:00:00
Verifico los datos en la base de datos usando phpMyAdmin y veo 2020-10-13 19:00:00. Todo está bien. La zona horaria de la PC es igual a la zona horaria de la base de datos, por lo que vemos el mismo resultado.
El programa está abierto en una PC con una zona horaria de +6: 30 (Yangon)
Console.WriteLine (obj.DateTime? .ToString ()); // 13.10.2020 22:30:00
Verifico los datos en la base de datos usando phpMyAdmin y veo 2020-10-13 22:30:00. ¡Fallar! Debería haber visto todo a la misma hora a las 19:00, no a las 22:30. ¡La propiedad obj.DateTime contenía la misma hora!
¿Cómo puedo entender ahora que estos registros contienen el mismo tiempo ? ¿Por qué EF no transfiere DateTime a UTC?
Respuestas
Si desea guardar la base de DateTime en la zona específica, no en la hora del servidor, le sugiero que cree un servicio, y cada vez que, en lugar de llamar a DateTime, llame a ese servicio. hay una clase llamada TimeZoneInfo que representa cualquier zona horaria del mundo y está disponible en el espacio de nombres del sistema .
Asegúrese de no usar DateTime para obtener la fecha actual directamente
DateTime now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"));
Esto convierte una hora universal coordinada (UTC) a la hora de una zona horaria especificada. Puede encontrar más información sobre los identificadores de zona enhttps://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-time-zones
Si está usando la inyección de dependencia:
public class DateTimeService : IDateTime
{
public DateTime Now => TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"));
}
public interface IDateTime
{
DateTime Now { get; }
}
o si prefiere usar una clase auxiliar:
public static class DateTimeHelper
{
public static DateTime Now() => TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"));
}