Jak poprawnie zapisać DateTime za pomocą Entity Framework Core?
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:
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.
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
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"));
}