Unix Timestamp: разница между использованием ToUnixTimeMilliseconds и TimeSpan.TotalMilliseconds - PullRequest
0 голосов
/ 16 ноября 2018

Я конвертирую DateTime в Unix время.Как я понимаю, эти два способа должны возвращать один и тот же результат.

Опция 1

DateTime dtfoo = new DateTime(2010, 10, 20);
DateTimeOffset dtfoo2 = new DateTimeOffset(dtfoo).ToUniversalTime();
long afoo = dtfoo2.ToUnixTimeMilliseconds();

Опция 2

DateTime dtfoo = new DateTime(2010, 10, 20);
DateTimeOffset dtfoo2 = new DateTimeOffset(dtfoo).ToUniversalTime();
long afoo = (Int64)(dtfoo2.Subtract(new DateTime(1970, 1, 1))).TotalMilliseconds;

Опция 1 возвращает 1287525600000, а Опция 2 возвращает 1287529200000.

Почему я получаю разные результаты?

Ответы [ 2 ]

0 голосов
/ 16 ноября 2018

Обратите внимание: Я нахожусь в UTC + 9, и корень ваших проблем связан со смещением часового пояса, поэтому поймите, что время Unix, которое я вижу, может немного отличаться от вашего.


Разница заключается в том, как вы обрабатываете объекты даты.Из полученной разницы я предполагаю, что ваш часовой пояс - CET (или вы использовали rextester, который, я полагаю, находится в Германии).

Рассмотрим следующий код:

var dtfoo = new DateTime(2010, 10, 20);
var dtfoo2 = new DateTimeOffset(dtfoo);
var dtfoo3 = dtfoo2.ToUniversalTime();
  1. Первая строка создает DateTime с DateTimeKind «Не указано» .
  2. Вторая строка создает из этого DateTimeOffset объект.Поскольку DateTimeKind не указан, используется смещение системного времени от UTC.
  3. Третья строка преобразует эту дату в UTC.

Цитирование документации для #2:

Если значение DateTime.Kind равно DateTimeKind.Local или DateTimeKind.Unspecified, свойство DateTime нового экземпляра устанавливается равным dateTime, а свойство Offset устанавливается равным смещениютекущего часового пояса локальной системы.

Теперь давайте выпишем строку даты в формате туда и обратно для 1-3:

2010-10-20T00:00:00.0000000
2010-10-20T00:00:00.0000000+09:00
2010-10-19T15:00:00.0000000+00:00

Я в UTC + 9, поэтомуDateTimeOffset был правильно создан со смещением + 9ч.Преобразование этого в универсальное приводит нас к 3 вечера 19-го.К сожалению, это приводит к выводу .ToUnixTimeMilliseconds() равным 1287500400000, что составляет 2010-10-19T15:00:00Z.Значение стало зависеть от часового пояса машины.

Итак, теперь давайте посмотрим на ваш второй пример:

DateTime dtfoo = new DateTime(2010, 10, 20);
DateTimeOffset dtfoo2 = new DateTimeOffset(dtfoo).ToUniversalTime();
long afoo = (Int64)(dtfoo2.Subtract(new DateTime(1970, 1, 1))).TotalMilliseconds;

ОК, давайте разделим это на различные части, чтобы мы моглипосмотрите, во сколько система думает, что они представляют (помните, что я в UTC + 9):

  1. new DateTime(2010, 10, 20).ToString("o") - 2010-10-20T00: 00: 00.0000000
  2. new DateTimeOffset(dtfoo).ToString("o") - 2010-10-20T00: 00: 00.0000000 + 09: 00
  3. new DateTimeOffset(dtfoo).ToUniversalTime() - 2010-10-19T15: 00: 00.0000000 + 00: 00
  4. new DateTime(1970, 1, 1).ToString("o") - 1970-01-01T00: 00: 00.0000000

Итак, вы эффективно выполняете следующие вычисления:

(DateTimeOffset.Parse("2010-10-19T15:00:00.0000000+00:00") - DateTime.Parse("1970-01-01T00:00:00.0000000")).TotalMilliseconds

Это выводит 1287532800000, что соответствует 2010-10-20T00: 00: 00Z.Это дает правильный результат из-за того, как выполняется вычитание:

  1. DateTime равно неявно приведено к DateTimeOffset, что эквивалентно new DateTimeOffset(DateTime.Parse("1970-01-01T00:00:00.000000")) - это означаетчто обе входные даты прошли через одни и те же изменения часового пояса.
  2. Две даты для вычитания обе преобразуются в DateTime объекты путем вызова свойства DateTimeOffset .UtcDateTime.

Так как мы можем исправить ваш оригинальный пример?Мы можем вывести локальное смещение часового пояса из уравнения, указав смещение при построении DateTimeOffset:

DateTime dtfoo = new DateTime(2010, 10, 20);
DateTimeOffset dtfoo2 = new DateTimeOffset(dtfoo, TimeSpan.Zero).ToUniversalTime();
long afoo = dtfoo2.ToUnixTimeMilliseconds();

Теперь это дает нам то же значение, которое мы получили в предыдущем тесте: 1287532800000.Если мы упростим это с помощью DateTimeOffset.Parse, мы должны подтвердить, что мы на правильном пути:

Console.WriteLine(DateTimeOffset.Parse("2010-10-20T00:00:00Z").ToUnixTimeMilliseconds());

И мы можем видеть, что это также выдает 1287532800000.

Итак,В заключение, ваша проблема связана с тем, как конструктор DateTimeOffset(datetime) обрабатывает даты с DateTimeKind Unspecified или Local.Это искажает получающееся универсальное время в зависимости от часового пояса вашей машины.Это приводит к неправильному смещению времени Unix.Чтобы решить эту проблему, просто создайте свой DateTimeOffset одним из способов, которые я описал выше.

0 голосов
/ 16 ноября 2018

Разница может быть в том, что ToUnixTimeMilliseconds не требует дополнительных секунд для учета.

вот что говорит документация:

https://docs.microsoft.com/en-us/dotnet/api/system.datetimeoffset.tounixtimemilliseconds?view=netframework-4.7.2

Время Unix представляет количество секунд, прошедших с 1970-01-01T00: 00: 00Z (1 января 1970 года, в 12:00 UTC).Это не учитывает дополнительных секунд.Этот метод возвращает количество миллисекунд в Unix-времени.

Где, как TimeSpan.TotalMilliseconds не говорил об этом.

https://docs.microsoft.com/en-us/dotnet/api/system.timespan.totalmilliseconds?view=netframework-4.7.2

ThisСвойство преобразует значение этого экземпляра из тиков в миллисекунды.Это число может включать целые и дробные миллисекунды.

...