Jak poprawnie zapisać DateTime za pomocą Entity Framework Core?

Oct 31 2020

Mam klasę zawierającą właściwość DateTime. Jak poprawnie oszczędzać czas korzystając z Entity Framework Core? Poniżej podam przykład.

Używam formatu TIMESTAMP do przechowywania DateTime w bazie danych. Mam serwer i bazę danych (MySQL), które mają strefę czasową +3 (Moskwa).

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

Mam też program, który można uruchomić na PC różnych użytkowników. Program zapisuje obiekt zawierający właściwość DateTime w bazie danych:

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

Spójrzmy teraz na kilka sytuacji:


  1. Program uruchamia się na komputerze PC ze strefą czasową +3 (Moskwa)

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

Sprawdzam dane w bazie za pomocą phpMyAdmina i widzę 2020-10-13 19:00:00. Wszystko w porządku. Strefa czasowa komputera jest równa strefie czasowej bazy danych, więc widzimy ten sam wynik.


  1. Program jest otwarty na PC ze strefą czasową +6:30 (Yangon)

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

Sprawdzam dane w bazie za pomocą phpMyAdmina i widzę 2020-10-13 22:30:00. Zawieść! Powinienem był zobaczyć wszystko o 19:00, a nie o 22:30. Właściwość obj.DateTime zawierała ten sam czas!


Jak mogę teraz zrozumieć, że te rekordy zawierają taki sam czas ? Dlaczego plik EF nie przekazuje DateTime do UTC?

Odpowiedzi

ShervinIvari Oct 31 2020 at 12:30

Jeśli chcesz zapisać bazę DateTime w określonej strefie, a nie na serwerze, sugeruję utworzenie usługi i za każdym razem Zamiast dzwonić DateTime dzwonisz do tej usługi. istnieje klasa o nazwie TimeZoneInfo, która reprezentuje dowolną strefę czasową na świecie i jest dostępna w przestrzeni nazw systemu .

Upewnij się, że nie używasz daty i godziny do bezpośredniego pobierania bieżącej daty

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

Spowoduje to konwersję uniwersalnego czasu koordynowanego (UTC) na czas w określonej strefie czasowej. Więcej informacji o identyfikatorach stref można znaleźć whttps://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-time-zones

Jeśli używasz iniekcji zależności:

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

public interface IDateTime
{
    DateTime Now { get; }
}

lub jeśli wolisz używać klasy pomocniczej:

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