C # TimeSpan секунды и миллисекунды не синхронизированы - PullRequest
0 голосов
/ 25 февраля 2019

Я работаю над обновлениями программного обеспечения для моделирования пакетов, которое наша команда поддерживает и использует для тестирования других приложений, над которыми мы работаем.Два поля, которые хранятся в этих смоделированных пакетах, - это время Unix (секунды) и наносекунды.Это время, прошедшее в секундах и наносекундах с 1, 1, 1970 года. Мы используем c # для этого конкретного приложения и получаем истекшее время, используя объект TimeSpan как таковой.

TimeSpan ts = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

packet.SetTimeSeconds(Convert.ToUInt64(ts.Totalseconds));

packet.SetTimeNanoseconds(Convert.ToUInt64(1e6 * ts.Milliseconds));

Когда пакеты захваченыпри его назначении и отображении содержимого кажется, что значение секунд значительно отстает от значения наносекунд.Значение наносекунды поднимется до порогового значения, перевернется и снова начнет расти, но значение секунд требует несколько пакетов для пролонгации.Я проверил, обновляется ли значение секунд после установки в другом месте кода, но это не так.Остальные значения пакета устанавливаются после приведенного выше фрагмента, а затем пакет отправляется в пункт назначения с помощью сокета.

Я понимаю, что время для одного такта составляет 16 мс, и обновление может упасть между двумя пакетами.,Это может привести к их несогласованности на мгновение.В этом случае я бы ожидал, что они не будут соответствовать одному пакету максимум из-за частоты тиков.В моей ситуации это несоответствие происходит для 3 или 4 пакетов до обновления значения секунд при создании данных каждые 100 мс.

Важно отметить, что из-за рабочей среды я по закону не могу выложить полный исходный код онлайнтак что не спрашивай.Также я проверил всю логику после того, как время установлено в пакете, чтобы убедиться, что ничего не перезаписывается.Мой главный вопрос: если это просто проблема с DateTime.UtcNow или возможно получение точного истекшего времени с TimeSpan.Это не проблема создания или разрушения, поскольку это всего лишь симулятор, но было бы неплохо иметь точное смоделированное время в наших тестовых пакетах.

РЕДАКТИРОВАТЬ:

Для дополнительной информации проблемаЭто происходит даже тогда, когда я не использую свою структуру пакетов и не отправляю значения получателю.Я написал следующий цикл для проверки значений TimeSpan / DateTime без возможности использования другой логики.

for (int i = 0; i < 150; i++)
{

     TimeSpan temp = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

     Console.WriteLine("The seconds elapsed is: " + Convert.ToUInt64(temp.TotalSeconds) + " The nanoseconds portion: " + Convert.ToUInt64(1e6 * temp.Milliseconds);

}

Имейте в виду, что следующий цикл будет распечатывать несколько экземпляров одинаковых значений, посколькупроцессор может повторять цикл несколько раз между тактами (каждый такт занимает 16 мс).Если вы запустите цикл, вы увидите, что значение наносекунд увеличивается, как и ожидалось, до 999000000, а затем переворачивается, чтобы начать заново, когда достигается новая секунда.Когда вы увидите, что пролонгирование проверьте значение секунд, и вы заметите, что оно не обновилось.Я бы опубликовал распечатку, но моя машина с подключением к Интернету не имеет IDE.

Решение:

Как указывает принятый ниже ответ, я использовал convert.ToUInt64 для приведения значения TotalSeconds (двойной) Улонг.Это было сделано для удовлетворения наших внутренних библиотечных функций.Это приведение округляет значение секунд, в результате чего значение представляется неточным.В итоге я использовал функцию Math.Floor (double), чтобы убрать фрактальную часть секунд до приведения, и все осталось в синхронизации.Мой обновленный код указан ниже.

TimeSpan ts = (DateTime.UtcNow - новый DateTime (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

packet.SetTimeSeconds(Convert.ToUInt64(Math.Floor(ts.Totalseconds)));

packet.SetTimeNanoseconds(Convert.ToUInt64(1e6 * ts.Milliseconds));

1 Ответ

0 голосов
/ 25 февраля 2019

Я не вижу никаких несоответствий.Ниже приведен объект TimeSpan, полученный из вашего кода.

TimeSpan.TicksPerMillisecond    : 10,000
TimeSpan.TicksPerDay            : 864,000,000,000

Ticks               : 15511159080437769         1551115908043.7769  milliseconds

Days                : 17952                     1551052800000       milliseconds
Hours               : 17                             61200000       milliseconds
Minutes             : 31                              1860000       milliseconds
Seconds             : 48                                48000       milliseconds
Milliseconds        : 43                                   43       milliseconds
Sum                 :                           1551115908043       milliseconds (NOTE: we don't have microsecond or nanosecond value bearing properties)

TotalDays           : 17952.730417173341        15511159080437769.0 / TimeSpan.TicksPerDay
TotalHours          : 430865.53001216019        15511159080437769.0 / TimeSpan.TicksPerHour
TotalMinutes        : 25851931.800729614        15511159080437769.0 / TimeSpan.TicksPerMinute
TotalSeconds        : 1551115908.0437768        15511159080437769.0 / TimeSpan.TicksPerSecond
TotalMilliseconds   : 1551115908043.7769        15511159080437769.0 / TimeSpan.TicksPerMillisecond

Как видите, все значения рассчитаны на основе уровня TimeSpan.Ticks.Вы можете рассчитать

ОБНОВЛЕНИЕ:

Используйте приведенный ниже код, чтобы получить правильное значение только для доли наносекунды или общего промежутка времени в наносекундах

public static class TimeSpanExtension {
    const decimal TicksPerNanosecond = TimeSpan.TicksPerMillisecond / 1000000m;
    public static decimal GetTotalNanoSeconds(this TimeSpan ts) => ts.Ticks / TicksPerNanosecond;
    public static decimal GetMicroAndNanoSeconds(this TimeSpan ts) => ts.Ticks % TimeSpan.TicksPerMillisecond / TicksPerNanosecond;
}

ОБНОВЛЕНИЕ2:

Из ваших обновлений кода в вопросе я заметил, что вы используете Convert.ToUInt64 для округления количества секунд, что приводит вас в замешательство.

Console.WriteLine("The seconds elapsed is: " + Convert.ToUInt64(temp.TotalSeconds) +
                    " The nanoseconds portion: " + Convert.ToUInt64(1e6 * temp.Milliseconds));

ВместоПриведенный выше код, вы должны использовать приведенный ниже код, чтобы убедиться в отсутствии противоречий.Вы можете видеть, как TotalSeconds переворачивается вместе с Milliseconds, но Convert.ToUInt64(temp.TotalSeconds) не будет опрокидываться

// C# 6.0 string interpolation syntax
Console.WriteLine($"{temp.TotalSeconds}, {Convert.ToUInt64(temp.TotalSeconds)}, {temp.Milliseconds,000}");

// similar statement without string interpolation
Console.WriteLine(temp.TotalSeconds + ", " + Convert.ToUInt64(temp.TotalSeconds) + ", " + temp.Milliseconds);
...