Проблема TimeZoneInfo.ConvertTimeToUtc
У нас была проблема, когда один разработчик создает код ниже, и он работает на его среде DEV. Но когда он проверяется в QA, код прерывается с приведенным ниже сообщением об ошибке:
myRecord.UTCStartTime = TimeZoneInfo.ConvertTimeToUtc(myRecord.StartTime, myTimeZone);
Преобразование не может быть завершено, потому что в поставляемом DateTime не было правильно задано свойство Kind. Например, когда свойство Kind является DateTimeKind.Local, часовой пояс источника должен быть TimeZoneInfo.Local.
В моей среде DEV приведенный выше код генерирует ту же ошибку, что и сервер QA. Я применил следующее изменение, чтобы исправить проблему:
DateTime utcStart = DateTime.SpecifyKind(myRecord.StartTime, DateTimeKind.Unspecified);
myRecord.UTCStartTime = TimeZoneInfo.ConvertTimeToUtc(utcStart, myTimeZone);
Почему первый пример кода работает в среде DEV1, но прерывается в моей среде DEV и на нашем сервере QA?
Ответы
Ответ 1
Это зависит от того, как был создан myRecord.StartTime
.
- Если вы получили его из
DateTime.Now
, тогда он будет иметь Local
вид. - Если вы получили его из
DateTime.UtcNow
то он будет иметь вид Utc
. - Если вы получили его из
new DateTime(2013,5,1)
то он будет иметь Unspecified
.
Это также зависит от того, откуда вы получили myTimeZone
. Например:
-
TimeZoneInfo.Local
-
TimeZoneInfo.Utc
-
TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
Функция TimeZoneInfo.ConvertTimeToUtc
будет работать только в том случае, если она может соответствовать зоне, которую вы ей даете. Если оба являются локальными, или оба являются UTC, то он будет работать. Если вы даете ему определенную зону, то тип должен быть неуказанным. Это поведение задокументировано в MSDN.
Вы можете легко воспроизвести исключение последовательно:
var tz = TimeZoneInfo.FindSystemTimeZoneById("Fiji Standard Time");
var utc = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now, tz);
Предполагая, что вы не живете на Фиджи, это будет ошибкой каждый раз. Вы в основном сказали: "Преобразуйте свое местное время, в какую-то другую зону, в utc" - это не имеет смысла.
Вероятно, он работает в вашей среде разработчиков, потому что ценность, которую вы тестируете для myTimeZone
, является локальной зоной для разработчика.
Что касается вашего изменения - убедитесь, что вы можете заставить этот вид быть неуказанным, и это изменяет смысл того, что вы делаете, чтобы это имело смысл. Но вы уверены, что это то, что вы хотите? Что такое .Kind
даты перед рукой? Если это еще не Unspecified
, то это несет некоторые намерения. Вероятно, вам следует вернуться к источнику этих данных и убедиться, что это то, что вы ожидаете.
Если все это звучит сумасшедшим, безумным, расстраивающим и причудливым, это потому, что объект DateTime
воняет. Вот несколько дополнительных чтений:
Вместо этого вы можете использовать NodaTime. Его API не позволит вам совершать подобные ошибки.
Ответ 2
используйте Datetime.SpecifyKind
:
var localDateTime = DateTime.SpecifyKind(localDate, DateTimeKind.Unspecified);
var utcDateTime = TimeZoneInfo.ConvertTimeToUtc(localDateTime, timeZoneId);
Ответ 3
Я нашел очень простое решение здесь https://kiranpatils.wordpress.com/2011/01/09/the-conversion-could-not-be-completed-because- theupupied-datetime-did-not-have -kind-свойство набор-правильно-для-например, когда-The-род-свойство-это-datetimekind-локальный-The-источник-часовой пояс-должен/
Кажется, что это происходит только при использовании DateTime.Now. Я обновляю свой код, как показано ниже, и он снова работает :)
DateTime currentTime = new DateTime (DateTime.Now.Ticks, DateTimeKind.Unspecified);
Ответ 4
в этом примере я преобразовал локальный часовой пояс в неуказанный тип, поэтому он отлично работает для меня, используя метод DateTime.SpecifyKind()
DateTime.SpecifyKind (МСВ, DateTimeKind.Unspecified);
этот метод Создает новый объект DateTime, который имеет такое же количество тиков, что и указанное DateTime, но обозначается как неопределенный тип DateTimeKind.
public static DateTime ConvertLocalDate (DateTime utc) {
string id = ConfigurationManager.AppSettings["Timezone"].ToString();
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById(id);
utc = DateTime.SpecifyKind(utc,DateTimeKind.Unspecified);
DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(utc, cstZone);
return cstTime;
}
Ответ 5
в С#
public static DateTime IndianDateTime(DateTime currentTime)
{
DateTime cstTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(currentTime, TimeZoneInfo.Local.Id, "India Standard Time");
return cstTime;
}
В VB
Public Shared Function IndianDateTime(ByVal currentTime As DateTime) As DateTime
Dim cstTime As DateTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(currentTime, TimeZoneInfo.Local.Id, "India Standard Time")
Return cstTime
End Function