¿Cómo guardar correctamente DateTime usando Entity Framework Core?

Oct 31 2020

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:


  1. 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.


  1. 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

ShervinIvari Oct 31 2020 at 12:30

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"));
}