C# TimeZoneInfo.ConvertTimeToUtc问题

C# TimeZoneInfo.ConvertTimeToUtc问题,c#,.net,datetime,C#,.net,Datetime,我们遇到了一个问题,一个开发人员创建了下面的代码,并在他的开发环境中工作。但是,当它签入QA时,代码会中断,并显示以下错误消息: myRecord.UTCStartTime = TimeZoneInfo.ConvertTimeToUtc(myRecord.StartTime, myTimeZone); 无法完成转换,因为提供的日期时间无效 未正确设置种类属性。例如,当 Kind属性为DateTimeKind.Local,源时区必须为 TimeZoneInfo.Local 在我的开发环境中,上面

我们遇到了一个问题,一个开发人员创建了下面的代码,并在他的开发环境中工作。但是,当它签入QA时,代码会中断,并显示以下错误消息:

myRecord.UTCStartTime = TimeZoneInfo.ConvertTimeToUtc(myRecord.StartTime, myTimeZone);
无法完成转换,因为提供的日期时间无效 未正确设置种类属性。例如,当 Kind属性为DateTimeKind.Local,源时区必须为 TimeZoneInfo.Local

在我的开发环境中,上面的代码生成与QA服务器相同的错误。我应用了以下更改来修复此问题:

DateTime utcStart = DateTime.SpecifyKind(myRecord.StartTime, DateTimeKind.Unspecified);
myRecord.UTCStartTime = TimeZoneInfo.ConvertTimeToUtc(utcStart, myTimeZone);

为什么第一个代码示例在DEV1的环境中工作,但在我的开发环境和我们的QA服务器上中断?

这取决于
myRecord.StartTime
是如何产生的

  • 如果您从
    DateTime.Now
    获得它,那么它将具有
    Local
    类型
  • 如果您从
    DateTime.UtcNow
    获得它,那么它将具有
    Utc
    类型
  • 如果您从
    newdatetime(2013,5,1)
    获得它,那么它将具有
    未指定的类型
这还取决于您从哪里获得
myTimeZone
。例如:

  • TimeZoneInfo.Local
  • TimeZoneInfo.Utc
  • TimeZoneInfo.FindSystemTimeZoneById(“中央标准时间”)
TimeZoneInfo.ConvertTimeToUtc
功能只有在能够将区域与您提供的类型相匹配的情况下才会运行。如果两者都是本地的,或者都是UTC的,那么它将工作。如果你给它一个特定的区域,那么类型应该是未指定的。这种行为是不公平的

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

var tz = TimeZoneInfo.FindSystemTimeZoneById("Fiji Standard Time");
var utc = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now, tz);
假设你不住在斐济,每次都会出错。你基本上是说,“将我的本地时间,在其他区域,转换为utc”——这没有意义

它可能在您的开发环境中工作,因为您测试的
myTimeZone
值恰好是开发人员的本地区域

关于你的改变——确保你可以强迫你的改变是不确定的,并且这会改变你所做的事情的意义,使之有意义。但你确定这就是你想要的吗?手上日期的种类是什么?如果它尚未
未指定
,则它带有某种意图。您可能应该回到这些数据的来源,并确保它是您所期望的

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


<>你可以考虑使用。它的API将防止您犯这些常见错误。

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

DateTime.SpecifyKind(utc,DateTimeKind.Unspecified)

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

公共静态日期时间转换器LocalDate(日期时间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;
    }

我在这里找到了一个非常简单的解决方案

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

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

在C中#

在VB中


基本上是前面的答案中所说的,但要精简一下:

DateTime.Now
DateTime.Today
将种类设置为
Local
,因此将其更改为
Unspecified

在处理日期的方法中:

//传入日期具有DateTimeKind.Local
var localDateTime=DateTime.Now;
//设置为未指定
var unspecifiedDateTime=DateTime.SpecifyKind(localDateTime,DateTimeKind.Unspecified);

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

您可以使用DateTime.Ticks来解决本地/Utc不兼容的问题。就像这样,当我从表中读取Utc时间时:var timeUtc=new DateTime(r.GetDateTime(r.GetOrdinal)(“timeUtc”))).Ticks,DateTimeKind.Utc);这只是设置种类的更复杂的方法。您可以使用
DateTime.SpecifyKind
获得相同的设置。

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

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