Обратите внимание: Я нахожусь в UTC + 9, и корень ваших проблем связан со смещением часового пояса, поэтому поймите, что время Unix, которое я вижу, может немного отличаться от вашего.
Разница заключается в том, как вы обрабатываете объекты даты.Из полученной разницы я предполагаю, что ваш часовой пояс - CET (или вы использовали rextester, который, я полагаю, находится в Германии).
Рассмотрим следующий код:
var dtfoo = new DateTime(2010, 10, 20);
var dtfoo2 = new DateTimeOffset(dtfoo);
var dtfoo3 = dtfoo2.ToUniversalTime();
- Первая строка создает
DateTime
с DateTimeKind
«Не указано» . - Вторая строка создает из этого
DateTimeOffset
объект.Поскольку DateTimeKind не указан, используется смещение системного времени от UTC. - Третья строка преобразует эту дату в 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):
new DateTime(2010, 10, 20).ToString("o")
- 2010-10-20T00: 00: 00.0000000 new DateTimeOffset(dtfoo).ToString("o")
- 2010-10-20T00: 00: 00.0000000 + 09: 00 new DateTimeOffset(dtfoo).ToUniversalTime()
- 2010-10-19T15: 00: 00.0000000 + 00: 00 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.Это дает правильный результат из-за того, как выполняется вычитание:
-
DateTime
равно неявно приведено к DateTimeOffset
, что эквивалентно new DateTimeOffset(DateTime.Parse("1970-01-01T00:00:00.000000"))
- это означаетчто обе входные даты прошли через одни и те же изменения часового пояса. - Две даты для вычитания обе преобразуются в
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
одним из способов, которые я описал выше.