Есть фундаментальная проблема с тем, как вы обрабатываете даты здесь, и если я сведу это к одной вещи, я думаю, проблема в том, что ToUniversalTime()
не работает так, как вы думаете.
То, что ToUniversalTime()
делает, просто дает UTC
время, определенное в другом часовом поясе. Например, скажем, мое местное время - UTC-7
. Поэтому, если я определяю DateTime
объект без указания DateTimeKind
и устанавливаю значение, скажем, 2017/6/1 9:00:00
, это означает, что в то время фактическое UTC
время будет 2017/6/1 16:00:00
при этом время, и ToUniversalTime()
даст вам DateTime
объект с этим значением.
Позвольте мне немного изменить ваш ToUTCString()
метод и показать вам проблему с ним. Теперь он возвращает long
вместо string
, и я разбиваю первую строку кода на две.
public static long ToUTC(this DateTime _input)
{
var utcTime = _input.ToUniversalTime();
var totalSeconds = utcTime.Subtract(UnixEpoch).TotalSeconds;
return Convert.ToInt64(totalSeconds);
}
И обратите внимание, что в вашем Extensions
классе объект UnixEpoch
DateTimeKind
установлен на UTC
. Я изменил дату на 2017/6/1 8:00:00
для простоты понимания.
private static readonly DateTime UnixEpoch = new DateTime(2017, 6, 1, 8, 0, 0, DateTimeKind.Utc);
public static DateTime ToDateTime(this Int64 _input)
{
return UnixEpoch.AddSeconds(_input);
}
Теперь давайте вызовем этот метод с DateTime
объектом, для которого DateTimeKind
имеет значение UTC
.
// dateObj will have time 2017/6/1 9:00:00 _in UTC_.
var dateObj = new DateTime(2017, 6, 1, 9, 0, 0, DateTimeKind.Utc);
// This method converts to UTC, but it's already in UTC, so no actual conversion takes place.
// Then subtracts UnixEpoch from it, which is also in UTC.
long dateInLong = dateObj.ToUTC();
// The difference is one hour, so dateInLong will be 3600.
Console.WriteLine(dateInLong);
// This method adds the above difference to UnixEpoch, and displays the time.
Console.WriteLine(dateInLong.ToDateTime());
Теперь здесь все в UTC
, и вы должны увидеть результат, как и ожидалось, как показано ниже:
3600
6/1/2017 09: 00: 00
Пока все хорошо.
Теперь немного изменим ситуацию, и давайте установим наш dateObj
на локальный вместо UTC
, как вы делаете в своем примере.
// Notice that the object is in local time now.
var dateObj = new DateTime(2017, 6, 1, 9, 0, 0);
long dateInLong = dateObj.ToUTC();
Console.WriteLine(dateInLong);
Console.WriteLine(dateInLong.ToDateTime());
Теперь у вышеупомянутого dateObj
будет время 9:00:00
, , но в моем местном времени . Мое фактическое местоположение - UTC-7
, поэтому обратите внимание, что для меня это означает 9AM
по местному времени 4PM
UTC. Но обратите внимание, что мы не изменили объект UnixEpoch
, который все еще находится в UTC
, и в нем установлено время 8AM UTC
. И, следовательно, dateInLong
будет 28,800
(8 часов x 60 минут x 60 секунд). Поэтому, когда вызывается ваш метод ToDateTime()
, он добавляет 28,000
секунд к 8AM UTC
времени и возвращает как DateTime
объект, время которого сейчас равно 4PM UTC
.
28800
6/1/2017 16: 00: 00
И именно поэтому в зависимости от времени, которое вы установили для dateObj
, ваш выходной сигнал меняет время, как вы сказали.
Решение
Вам нужно решить, какой часовой пояс использовать, и придерживаться этого. Один из вариантов - избавиться от всех преобразований UTC
и установить время по местному времени.
public static class Extensions
{
// NOT set to UTC
private static readonly DateTime UnixEpoch = new DateTime(2017, 6, 1, 8, 0, 0);
public static DateTime ToDateTime(this Int64 _input)
{
return UnixEpoch.AddSeconds(_input);
}
public static long ToUTC(this DateTime _input)
{
// NOT converted to UTC. So... change variable names accordingly.
var utcTime = _input;
var totalSeconds = utcTime.Subtract(UnixEpoch).TotalSeconds;
return Convert.ToInt64(totalSeconds);
}
}
class Program
{
static void Main(string[] args)
{
// Notice that the object is in local time and NOT UTC.
var dateObj = new DateTime(2017, 6, 1, 9, 0, 0);
long dateInLong = dateObj.ToUTC();
Console.WriteLine(dateInLong);
Console.WriteLine(dateInLong.ToDateTime());
Console.ReadLine();
}
}
Другой вариант - установить для ВСЕГО значение UTC, но тогда вам необходимо убедиться, что объект DateTime
, для которого вы вызываете ToUTC()
, определен в UTC, а не локально.
Итак:
private static readonly DateTime UnixEpoch = new DateTime(2017, 6, 1, 8, 0, 0, DateTimeKind.Utc);
И
var utcTime = _input.ToUniversalTime();
И, наконец,
var dateObj = new DateTime(2017, 6, 1, 9, 0, 0, DateTimeKind.Utc);
НО ...
Я вижу большую проблему с вашим кодом, глядя на второй фрагмент кода. В конструкторе ForecastIORequest()
вы экономите время как string
. И это не идеальное решение, на мой взгляд. Потому что, поскольку вы нашли трудный путь, в зависимости от того, в каком часовом поясе был создан вызывающий объект, ваша разница во времени будет, ну, в общем, разной. И ты не сможешь узнать, что именно.
Я бы предпочел сохранить объект DateTime
в том виде, как он есть, прочитать его и вычислить разницу при необходимости с учетом часовых поясов.
Надеюсь, это поможет.