Как правильно сохранить DateTime с помощью Entity Framework Core?

Oct 31 2020

У меня есть класс, содержащий свойство DateTime. Как правильно сэкономить время с помощью Entity Framework Core? Ниже я приведу пример.

Я использую формат TIMESTAMP для хранения DateTime в базе данных. У меня есть сервер и база данных (MySQL) с часовым поясом +3 (Москва).

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

Еще у меня есть программа, которую могут запускать на ПК разных пользователей. Программа сохраняет в базе данных объект, содержащий свойство DateTime:

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

Теперь рассмотрим несколько ситуаций:


  1. Программа запускается на ПК с часовым поясом +3 (Москва)

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

Я проверяю данные в базе данных с помощью phpMyAdmin и вижу 2020-10-13 19:00:00. Все нормально. Часовой пояс ПК равен часовому поясу базы данных, поэтому мы видим тот же результат.


  1. Программа открыта на ПК с часовым поясом +6:30 (Янгон)

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

Я проверяю данные в базе данных с помощью phpMyAdmin и вижу 2020-10-13 22:30:00. Неудача! Я должен был увидеть все одновременно в 19:00, а не в 22:30. Свойство obj.DateTime содержало то же время!


Как мне теперь понять, что эти записи содержат одинаковое время ? Почему EF не передает DateTime в UTC?

Ответы

ShervinIvari Oct 31 2020 at 12:30

Если вы хотите сохранить базу DateTime для определенной зоны, а не для серверного времени, я предлагаю вам создать службу, и каждый раз вместо вызова DateTime вы вызываете эту службу. есть класс TimeZoneInfo, который представляет любой часовой пояс в мире и доступен в системном пространстве имен.

Убедитесь, что вы не используете DateTime для получения текущей даты напрямую

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

Это преобразует всемирное координированное время (UTC) во время в указанном часовом поясе. Вы можете найти больше об идентификаторах зон вhttps://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-time-zones

Если вы используете инъекцию зависимостей:

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

public interface IDateTime
{
    DateTime Now { get; }
}

или если вы предпочитаете использовать вспомогательный класс:

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