关于c#:TimeZoneInfo.ConvertTimeToUtc问题

TimeZoneInfo.ConvertTimeToUtc issue

我们遇到一个问题,一个开发人员创建下面的代码,它可以在他的DEV环境中工作。 但是当它被检入QA时,代码会出现以下错误消息:

1
myRecord.UTCStartTime = TimeZoneInfo.ConvertTimeToUtc(myRecord.StartTime, myTimeZone);

The conversion could not be completed because the supplied DateTime
did not have the Kind property set correctly. For example, when the
Kind property is DateTimeKind.Local, the source time zone must be
TimeZoneInfo.Local.

在我的DEV环境中,上面的代码生成与QA服务器相同的错误。 我应用以下更改来解决问题:

1
2
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上记录了此行为。

您可以轻松地一致地重现异常:

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

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

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

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

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

  • 无论如何,DateTime有什么问题?
  • 针对DateTime.Now的案例

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


在这个例子中我已经将本地时区转换为未指定的类型,因此通过使用"DateTime.SpecifyKind()"方法它对我来说很好

DateTime.SpecifyKind(utc,DateTimeKind.Unspecified);

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

public static DateTime ConvertLocalDate(DateTime utc)
{

1
2
3
4
5
6
        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;
    }


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

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

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


在C#中

1
2
3
4
5
public static DateTime IndianDateTime(DateTime currentTime)
{
    DateTime cstTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(currentTime, TimeZoneInfo.Local.Id,"India Standard Time");
    return cstTime;
}

在VB中

1
2
3
4
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