.net中的日期差异出错

时间:2014-12-24 09:00:32

标签: .net

我正在使用以下代码段

lxDate= #1/1/1970#
GetUnixDate = CType(DateDiff("S", lxDate, pDate), Int32)

其中pDate是用户输入的日期及其格式 mm / dd / yyyy例如第12/24/2014年# 这会正确检索unix日期。但是在一台特定的机器上,输出比所需日期少一秒。 这是转换结果在上一个日期时的unix时间戳。 例如,星期六,2004年12月18日23:59:59当期望结果为
时,检索GMT 太阳,2004年12月19日00:00:00 GMT

1 个答案:

答案 0 :(得分:2)

是的,这在技术上是可行的。 DateDiff()使用Math.Round()从TimeSpan.TotalSeconds生成返回值。像这样的浮点数学容易受到在改变FPU控制字的机器上运行的行为不端的代码的攻击。控制字中的两个设置可能导致像这样的一个错误,精度设置和舍入模式。

此类代码可以通过各种方式感染您的程序。通常的麻烦制造者是打印机驱动程序,一些Hewlett Packard驱动程序已知有此错误。或者是一个shell扩展,它们会被加载到你的进程中,比如一个OpenFileDialog。更晦涩的方式是DirectX,它可以改变精度设置。众所周知,Microsoft ACE数据提供程序的一个版本会搞砸舍入模式。

到目前为止,解决此问题的最佳方法是重新成像机器。如果您没有在计算机上安装调试器,则很难找到DLL。并且它可能导致其他程序以非常难以诊断的方式行为不端。如果你有调试器,This post会有调试提示。

但是你可能只是想把你的盘子弄掉。您可以通过使用此代码避免浮点数学运算来实现,将其放在模块中:

Public Function UnixTimestamp(ByVal dt As DateTime) As Integer
    Dim span = dt.ToUniversalTime() - New DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)
    Return CInt(span.Ticks \ 10000000)
End Function

演示此问题的示例程序:

Imports System.Runtime.InteropServices

Module Module1
    Sub Main()
        SetFpuRoundingMode(RoundingMode.Down)  '' or Chop
        Dim lxDate = #1/1/1970#
        Dim pDate = #12/24/2014#
        Dim unix = CType(DateDiff("S", lxDate, pDate), Int32)
        System.Diagnostics.Debug.Assert(unix = 1419379200)
    End Sub

    Enum RoundingMode
        Near
        Down
        Up
        Chop
    End Enum

    Sub SetFpuRoundingMode(mode As RoundingMode)
        _controlfp(mode << 8, &H300)
    End Sub

    <DllImport("msvcrt.dll", CallingConvention:=CallingConvention.Cdecl)> _
    Friend Function _controlfp(bits As Integer, mask As Integer) As Integer
    End Function
End Module

这为您提供了另一种解决方法,您可以使用SetFpuRoundingMode(RoundingMode.Near)来恢复FPU。然而,确切地说那个电话就是你必须要弄清楚的。