Разница в сравнении DateTime и проанализированных DateTimeOffset тиков - PullRequest
1 голос
/ 24 сентября 2019

У меня есть два приложения.Клиентское приложение и серверное приложение.

Клиентское приложение отправляет HTTP-запрос на сервер, где тело запроса содержит DateTime.

На сервере, который я получаю, DateTimeпреобразуйте его в Ticks и сохраните в базе данных SQLite.(Вы можете поспорить о том, почему Ticks, но именно так строится это приложение ..)

Пока все хорошо.

Не намного позже (через несколько минут) серверное приложение выполняетзапрос к базе данных, где он пытается запросить все записи за последние 30 минут.

В коде я делаю что-то вроде этого, чтобы получить текущий DateTime минус 30 минут:

DateTimeOffset.Now.AddMinutes(-30).Ticks;

По какой-то причине это число больше, чем отметка времени вновь созданных записей.

Возможно, я что-то упускаю, но просто не вижу этого ...

Вот фрагмент кода, который идеально имитирует мою проблему.(Ссылка на рабочий демо внизу поста)

public static void Main()
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Client app
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    var clientTimestamp = DateTimeOffset.Now.DateTime;
    var jsonDateTime = clientTimestamp.ToString("yyyy-MM-ddThh:mm:ss.fffZ");


    // Then, the client app sends data as JSON to the server app...


    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Server app
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    // Mimick as if we received a json string with a DateTime in it. Parse that back to a real DateTime object.
    // This is also the value that will be stored in the database
    var serverDateTime = DateTime.Parse(jsonDateTime);
    Console.WriteLine("Ticks serverDateTime:             " + serverDateTime.Ticks.ToString());


    // A minute or so later, a recurring job checks the database for newly added records in the range of: 30 minutes ago till now.

    // Create a new DateTime Now minus 30 minutes... Both Ticks values below are greater than the jsonDateTime ticks?

    // DateTimeOffset:
    // This value is larger, even with the minus -10 minutes?
    var nowDateTimeOffset = DateTimeOffset.Now.AddMinutes(-10).Ticks.ToString();
    Console.WriteLine("Ticks nowDateTime -10 minutes:    " + nowDateTimeOffset);

    // DateTime
    // This value is larger, even with the minus -10 minutes?
    var nowDateTime = DateTimeOffset.Now.AddMinutes(-10).Ticks.ToString();
    Console.WriteLine("Ticks nowDateTime -10 minutes:    " + nowDateTime);
}

Вот демо: https://dotnetfiddle.net/58Un0p

1 Ответ

2 голосов
/ 25 сентября 2019

В этом случае, похоже, проблема в формате DateTime:

"yyyy-MM-ddThh:mm:ss.fffZ"  // lower hh

, тогда как оно должно быть:

"yyyy-MM-ddTHH:mm:ss.fffZ"  // upper HH

Использование 12 часов (hh)формат, а не 24-часовой (HH) формат будет вызывать разницу в 12 часов в 50% случаев!


Как упоминает Ганс в комментариях, вы должны убедиться, что вы используете UTC для сравненияЗначения DateTime.DateTime.Parse по умолчанию устанавливает тип DateTime на DateTimeKind.Local.Отправляет ли клиент UTC DateTime?

Обновите клиентскую метку времени, чтобы он отправлял UTC DateTime с ToUniversalTime:

var clientTimestamp = DateTimeOffset.Now.ToUniversalTime();

Вместо DateTime.Parse рассмотрите DateTime.ParseExact с AdjustToUniversal:

// convert the date to UTC before saving to database
var utcServerDate = DateTime.ParseExact(jsonDateTime, "yyyy-MM-ddTHH:mm:ss.fffZ", 
                         CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

А при сравнении значения DateTimeOffset.Now используйте UtcTicks:

var nowDateTimeOffset = DateTimeOffset.Now.AddMinutes(-30).UtcTicks;
...