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服务器上中断?

这取决于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上记录了此行为。

您可以轻松地一致地重现exception:

 var tz = TimeZoneInfo.FindSystemTimeZoneById("Fiji Standard Time"); var utc = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now, tz); 

假设你不住在斐济,每次都会出错。 你基本上说,“将我的当地时间,在其他一些区域转换为utc” – 这没有任何意义。

它可能适用于您的开发环境,因为您为myTimeZone测试的值恰好是开发人员的本地区域。

关于你的改变 – 确保你可以强制指出这种类型,并改变你正在做的事情的意义,这样才有意义。 但你确定这是你想要的吗? 什么是约会的.Kind ? 如果它还没有Unspecified ,那么它带有一些意图。 您应该回到这些数据的来源,并确保它符合您的期望。

如果所有这些听起来都疯狂,疯狂,令人沮丧和奇怪,那是因为DateTime对象很臭。 这是一些额外的阅读:

  • DateTime有什么问题?
  • 针对DateTime.Now的案例

您可以考虑使用NodaTime 。 它的API将阻止您犯这些类型的常见错误。

我在这里找到了一个非常简单的解决方案https://kiranpatils.wordpress.com/2011/01/09/the-conversion-could-not-be-completed-because-the-supplied-datetime-did-not-have-the -kind-属性-组-正确换例如-当最类型-属性-是-datetimekind本地最源的时区,必须/

这似乎只在您使用DateTime.Now时发生。 我更新我的代码如下,它再次工作:)

DateTime currentTime = new DateTime(DateTime.Now.Ticks,DateTimeKind.Unspecified);

在这个例子中,我已经将本地时区转换为未指定的类型,因此通过使用“DateTime.SpecifyKind()”方法它可以正常工作

DateTime.SpecifyKind(UTC,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; } 

在C#中

 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