Come salvare correttamente DateTime utilizzando Entity Framework Core?

Oct 31 2020

Ho una classe contenente una proprietà DateTime. Come risparmiare tempo correttamente utilizzando Entity Framework Core? Farò un esempio di seguito.

Uso il formato TIMESTAMP per memorizzare il DateTime nel database. Ho un server e un database (MySQL) con fuso orario +3 (Mosca).

SELECT TIMEDIFF(current_timestamp(), utc_timestamp()); // result = 03:00:00

Ho anche un programma che può essere eseguito sul PC di vari utenti. Il programma salva l'oggetto contenente la proprietà DateTime nel database:

obj.DateTime = DateTime.Parse("2020-10-13T19:00:00+0300");

Ora diamo un'occhiata ad alcune situazioni:


  1. Il programma viene avviato su un PC con fuso orario +3 (Mosca)

    Console.WriteLine(obj.DateTime?.ToString()); // 13-10-2020 19:00:00

Controllo i dati nel database usando phpMyAdmin e vedo 2020-10-13 19:00:00. Va tutto bene. Il fuso orario del PC è uguale al fuso orario del database, quindi vediamo lo stesso risultato.


  1. Il programma è aperto su un PC con fuso orario +6:30 (Yangon)

    Console.WriteLine(obj.DateTime?.ToString()); // 13.10.2020 22:30:00

Controllo i dati nel database usando phpMyAdmin e vedo 2020-10-13 22:30:00. Fallire! Avrei dovuto vedere tutto allo stesso tempo alle 19:00, non alle 22:30. La proprietà obj.DateTime conteneva la stessa ora!


Come posso ora capire che questi record contengono lo stesso tempo ? Perché l'EF non trasferisce DateTime all'UTC?

Risposte

ShervinIvari Oct 31 2020 at 12:30

Se vuoi salvare la base di DateTime sulla zona specifica, non sull'ora del server, ti suggerisco di creare un servizio e ogni volta invece di chiamare DateTime chiami quel servizio. esiste una classe chiamata TimeZoneInfo che rappresenta qualsiasi fuso orario nel mondo ed è disponibile nello spazio dei nomi di sistema .

Assicurati di non utilizzare DateTime per ottenere direttamente la data corrente

DateTime now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time")); 

Questo converte un'ora UTC (Coordinated Universal Time) nell'ora in un fuso orario specificato. Puoi trovare ulteriori informazioni sugli ID di zona inhttps://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-time-zones

Se stai usando l'iniezione di dipendenza:

public class DateTimeService : IDateTime
{
    public DateTime Now => TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"));
}

public interface IDateTime
{
    DateTime Now { get; }
}

o se preferisci usare una classe di supporto:

public static class DateTimeHelper
{
    public static DateTime Now() => TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"));
}