具有日期时间和UTC到本地时间转换的.NET奇怪行为

时间:2013-11-14 11:53:03

标签: vb.net datetime visual-studio-2005 .net-2.0

我正在修改和旧的应用程序,我发现了一个大错误。我在西班牙,这个应用程序正在读取一些包含UTC字符串格式的日期的文件,需要进行转换。

由于以下格式,字符串值已转换为CDate的本地时间:
"yyyy-MM-yyTHH:mmZ"

但是这里的代码再次将日期转换为.ToLocalTime的本地值,可能会使时间再次变为不正确的值。

现在出现了一个奇怪的事实,即var取正确的值,但代码没有返回。在Visual Studio的“检查”部分中,您可以看到结果应为0,而不是22(第二天的0小时)。

Visual Studio error

这里发生了什么?

修改

该应用正在读取XML文件,此时正在阅读:

<IntervaloTiempo v="2013-10-26T19:33Z/2013-10-26T22:00Z"/>

代码是屏幕截图中显示的代码:

Valor = Split(.Value, "/")

dtUTC = CDate(Valor(0)) 
iHoraIn = Hour(dtUTC.ToLocalTime().AddHours(1))

我用这个更正了代码,应用程序的工作方式相同:

iHoraIn = dtUTC.AddHours(1).Hour

EDIT2:

由于看起来我的帖子很难理解,如评论所示,我会尝试澄清一些事情。

我正在使用Visual Studio 2005和.NET Framework 2.0。

dtUTC中的值会转换为本地时间,其值(如屏幕截图所示)为21:33,应该22返回AddHour(1).Hour

使用dtUTC.ToLocalTime()时,其小时应转换为23:33值,该值应0返回AddHour(1).Hour

正如您在“检查”窗口中看到的那样,这就是行为。问题是,var iHoraIn的最终值是22,这是正确的,但代码不是。

实际上,将代码更改为仅删除ToLocalTime()部分会使最终值相同。

有人可以解释为什么以及如何发生这种情况?这是一个错误吗?

2 个答案:

答案 0 :(得分:1)

<强> DateTime.Kind

在.Net框架的2.0版本中,Microsoft引入了DateTime.Kind property。不同种类如下:

Local
Unspecified
Utc

每个Date(基础CLR类型为DateTime)对象都具有Kind属性,该属性指定该对象的日期类型。也就是说,它指定日期值是本地值,UTC还是未知。

如果Date对象具有Kind = Local,则在调用ToLocalTime函数时不会执行转换。从DateTime.ToLocalTime method开始,重点是我的:

Kind        Results (of ToLocalTime)
----------- -----------------------------------------
Utc         This instance of DateTime is converted to local time.
Local       No conversion is performed.
Unspecified This instance of DateTime is assumed to be a UTC time,
            and the conversion is performed as if Kind were UTC.

这对您的情况有何影响?

使用CDate时,生成的KindLocal。这意味着当您在其上调用ToLocal时,不会进行转换:

Dim valor = "2013-10-26T19:33Z"
Dim dtUTC = CDate(valor)
' dtUTC.Kind is Local
' The following does not do any conversion
Dim dtLocal = dtUTC.ToLocal()

更完整的示例

此示例显示使用CDate时会发生什么,以及明确设置Kind时会发生什么。前两个代码块是等效的 - CDate创建Local日期。第三个块显示指定UTC日期时会发生什么。

Sub Main()
    Dim valor = "2013-10-26T19:33Z"

    Dim dtUTC = CDate(valor)
    Dim dtLocal = dtUTC.ToLocalTime()
    Dim iHoraIn = Hour(dtLocal.AddHours(1))
    Dim kind = dtUTC.Kind
    printDate(dtUTC, dtLocal, iHoraIn, kind)

    Dim dtUTC2 = DateTime.SpecifyKind(dtUTC, DateTimeKind.Local)
    Dim dtLocal2 = dtUTC2.ToLocalTime()
    Dim iHoraIn2 = Hour(dtLocal2.AddHours(1))
    Dim kind2 = dtUTC2.Kind
    printDate(dtUTC2, dtLocal2, iHoraIn2, kind2)

    Dim dtUTC3 = DateTime.SpecifyKind(dtUTC, DateTimeKind.Utc)
    Dim dtLocal3 = dtUTC3.ToLocalTime()
    Dim iHoraIn3 = Hour(dtLocal3.AddHours(1))
    Dim kind3 = dtUTC3.Kind
    printDate(dtUTC3, dtLocal3, iHoraIn3, kind3)
End Sub

Sub printDate(ByVal dtUtc, ByVal dtLocal, ByVal hora, ByVal utcKind)
    System.Console.WriteLine("UTC: {0}, UTC KIND: {1}, LOCAL: {2}, HORA: {3}", dtUtc, utcKind, dtLocal, hora)
End Sub

以上产生了这个输出:

UTC: 2013-10-26 09:33:00 PM, UTC KIND: Local, LOCAL: 2013-10-26 09:33:00 PM, HORA: 22
UTC: 2013-10-26 09:33:00 PM, UTC KIND: Local, LOCAL: 2013-10-26 09:33:00 PM, HORA: 22
UTC: 2013-10-26 09:33:00 PM, UTC KIND: Utc, LOCAL: 2013-10-26 11:33:00 PM, HORA: 0

所以你所看到的不是一个错误 - 它是预期的行为。您正在尝试转换您认为的UTC日期;但实际上它实际上是一个当地的约会。

我相信你期望看到的是上面第三个代码块中发生的事情。它会创建一个UTC日期并将其转换为当地时间。

答案 1 :(得分:-1)

这里发生的是

Sub Main()
    Dim valor = "2013-10-26T19:33Z" 

    'this convert to local time
    Dim dtUTC = CDate(valor) 

    'this add one hour to local time in 24 hour format
    'equal to dtUTC.AddHours(1).Hour 
    Dim iHoraIn = dtUTC.ToLocalTime.AddHours(1).Hour 
End Sub

2013-10-26T19:33Z在我的时区2013-10-26 15:33dtUTC显示此时间

我要加1小时,所以iHoraIn现在是16


在您的屏幕截图中,观看节目dtUTC显示为9:33 PM 21小时

你加1小时,现在是22小时

这是你期望的吗?