我有一些从ODBC驱动程序(基于DSN字符串(带有用户名和密码)选择驱动程序)读取的.NET代码,该驱动程序从表中读取多个字段,其中一个字段是DateTime字段。该代码在SQL Server数据库/ ODBC驱动程序中的使用时间为100%,在大多数情况下,与MS Access数据库一起使用。但是,有时我会在特定行上得到“第2列(DateTimeColumn)上无效的日期时间格式”异常,甚至没有直接访问该列的情况(例如,即使我只是调用
reader.IsDBNull(someOtherColumn)
我仍然得到例外。
这似乎主要(仅?)是在Access数据库中已经填充了Excel中计算某些DateTimes的数据(例如,将datetime加1/24以获得下一个小时)时发生的。
如果我运行以下查询,该异常消失:
UPDATE MyTable Set DateTimeColumn = CDate(CStr(DateTimeColumn))
因此,似乎从Excel的日期时间计算到Access驱动程序的日期时间计算都涉及某种舍入误差。
由于某些数据是由创建自己的数据库的用户提供的,因此我将无法使用我的代码在其数据库上运行UPDATE查询。一种可能的“仅访问”解决方法是在我的SQL语句中调用CDate(CStr(DateTimeColumn)),但这不适用于SQL Server或其他数据库。
我仅使用可同时使用.mdb文件和.accdb文件的32位MS Access驱动程序(我的计算机上没有64位驱动程序进行测试)对此进行了测试,并且无论是否出现问题,都会出现此问题。数据位于.mdb文件或.accdb文件中。
编辑:
为了将来参考,Date/Time导致异常的Access数据库中的值0x40E4277FFFFFFFF8以十进制为
Date/Time
0x40E4277FFFFFFFF8
41275.9999999999417923390865326
同样可能引起关注的是,尽管该值在尝试通过an读取行时导致错误OdbcConnection,但使用an读取同一行OleDbConnection并 没有 引发异常。
OdbcConnection
OleDbConnection
考虑到更新后的问题中的测试数据,以下变通办法似乎可以正常工作。它检查.Driver打开的连接的属性,以查看它是否正在从Access数据库中读取。如果是这样,它将获取Date/Timeas的值Double,然后将其转换回System.DateTime。否则,它将仅从datetimeSQL Server正常检索。
.Driver
Double
System.DateTime
datetime
(请注意,此特定方法使用`rdr[0]) * 86400`''对于Access中早于的值(即,当值为负时) **将无法** 正常工作。)`Date/Time1899-12-30 00:00:00`Double
使用`rdr[0]) * 86400`''对于Access中早于的值(即,当值为负时) **将无法** 正常工作。)`Date/Time
`Double
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Odbc; namespace odbcTest { class Program { static void Main(string[] args) { using (OdbcConnection con = new OdbcConnection()) { //con.ConnectionString = // @"Driver={SQL Server};" + // @"Server=(local)\SQLEXPRESS;" + // @"Database=myDb;" + // @"Trusted_connection=yes;"; con.ConnectionString = @"Driver={Microsoft Access Driver (*.mdb, *.accdb)};" + @"Dbq=C:\__tmp\dateTest\TestSqlRead.accdb;"; con.Open(); using (OdbcCommand cmd = new OdbcCommand()) { DateTime dtm; var accessTime0 = new DateTime(1899, 12, 30); bool fromAccess = (con.Driver == "ACEODBC.DLL"); cmd.Connection=con; if (fromAccess) //cmd.CommandText = "SELECT DateTimeCol FROM MyTable"; // this fails cmd.CommandText = "SELECT {fn CDbl(DateTimeCol)} FROM MyTable"; else cmd.CommandText = "SELECT sqlDate FROM Table1 WHERE ID = 1"; OdbcDataReader rdr = cmd.ExecuteReader(); rdr.Read(); if (fromAccess) dtm = accessTime0.AddSeconds(Convert.ToDouble(rdr[0]) * 86400); else dtm = Convert.ToDateTime(rdr[0]); Console.WriteLine(dtm.ToString()); rdr.Close(); } con.Close(); } Console.WriteLine(); Console.WriteLine("Done."); Console.ReadKey(); } } }