66

我们遇到了一个问题,一位开发人员创建了以下代码,并且可以在他的 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 服务器上中断?

4

6 回答 6

97

这取决于它是如何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 将防止您犯这些类型的常见错误。

于 2013-05-01T17:45:08.240 回答
9

在此示例中,我已将本地时区转换为未指定类型,因此使用“DateTime.SpecifyKind()”方法对我来说工作正常

DateTime.SpecifyKind(utc,DateTimeKind.Unspecified);

此方法创建一个新的 DateTime 对象,该对象与指定的 DateTime 具有相同的刻度数,但被指定为 DateTimeKind 的未指定类型。

公共静态日期时间转换本地日期(日期时间 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;
    }
于 2015-12-21T11:07:31.230 回答
2

我在这里找到了一个非常简单的解决方案 https://kiranpatils.wordpress.com/2011/01/09/the-conversion-could-not-be-completed-because-the-supplied-datetime-did-not-have-the -kind-property-set-for-example-when-the-kind-property-is-datetimekind-local-the-source-time-zone-must/

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

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

于 2016-04-05T14:04:47.287 回答
0

基本上是以前的答案中所说的,但要减少它:

DateTime.NowDateTime.Today将 Kind 设置为Local,因此将其更改为Unspecified

在处理日期的方法中:

// Incoming date has DateTimeKind.Local 
 var localDateTime = DateTime.Now;

// Set to unspecified
 var unspecifiedDateTime = DateTime.SpecifyKind(localDateTime, DateTimeKind.Unspecified); 

我只是在部署时才收到这个,然后意识到一个库正在传递DateTime.Now而不是传递new DateTime(...)给一个方法。

于 2021-06-02T08:02:51.953 回答
0

接受的答案很好地解释了原因。但为了完整起见,我仍然加了 2 美分:

在序列化DateTime 对象时,某些序列化程序会弄乱Kind您的 DateTime 属性。我们在使用 ProtoBuf 和 MessagePack 序列化程序在 Redis 中缓存 POCO 对象时遇到了这个问题。

因此,如果您知道是这种情况,那么将 datetime 变量的类型强制为“未指定”是完全可以的,如下所示:

myDateTime = DateTime.SpecifyKind(myDateTime, DateTimeKind.Unspecified);
于 2021-11-28T11:21:55.963 回答
-2

在 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
于 2018-03-12T06:18:56.537 回答