我有一些从ODBC驱动程序读取的.NET代码(驱动程序是根据DSN字符串(使用用户名和密码)选择的)从表中读取多个字段,其中一个字段是DateTime字段。该代码100%使用SQL Server数据库/ ODBC驱动程序,大部分时间使用MS Access数据库。但是,有时我会在特定行上获得“第2列(DateTimeColumn)列上的无效日期时间格式”异常,甚至没有直接访问该列(例如,即使我只是调用
reader.IsDBNull(someOtherColumn)
我仍然得到例外。
这似乎主要(仅?)在Access数据库填充了Excel中的数据时发生了一些日期时间(例如,将日期时间加上1/24以获得下一个小时)。
如果我运行以下查询,则异常消失:
UPDATE MyTable Set DateTimeColumn = CDate(CStr(DateTimeColumn))
因此,Excel的计算日期时间与Access驱动程序计算日期时间之间似乎存在某种舍入错误。
由于某些数据是由创建自己的数据库的用户提供的,因此我无法使用我的代码在其数据库上运行UPDATE查询。一个可能的仅限Access的解决方法是在我的SQL语句中调用CDate(CStr(DateTimeColumn)),但这对SQL Server或其他数据库不起作用。
我只测试了32位MS Access驱动程序(我的机器上没有64位驱动程序来测试它们),它们同时适用于.mdb文件和.accdb文件,并且出现问题无论数据是在.mdb文件还是.accdb文件中。
编辑:
为了将来参考,导致异常的Access数据库中的Date/Time
值为0x40E4277FFFFFFFF8
,其中十进制为
41275.9999999999417923390865326
同样可能感兴趣的是,虽然此值在尝试通过OdbcConnection
读取行时导致错误,但使用OleDbConnection
读取同一行时不抛出例外。
答案 0 :(得分:1)
以下解决方法似乎可以根据更新的问题提供测试数据。它会检查打开连接的.Driver
属性,以查看它是否正在从Access数据库中读取。如果是,则会将Date/Time
值检索为Double
,然后将其转换回System.DateTime
。否则,它只是正常从SQL Server检索datetime
。
(请注意,这种方法可能 可能对Access中Date/Time
的值1899-12-30 00:00:00
正常工作,即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();
}
}
}
答案 1 :(得分:0)
没有。
Access使用自己的日期格式
'#2011-12-16#'
SQL-Server对日期值使用ISO标准:
20111216
和
2012-12-16THH:mm:ss.fff
for datetime
您可以做的是将日期值为字符串的表提取到System.Data.DataTable中,更正值,然后使用update将它们写回。更好的是,永远不要使用文本字段来存储日期/日期时间,并且你从来没有遇到过这个问题,因为它不会让你插入无效的日期时间值(好吧,也许Access会......)。
另外,如果您使用参数化查询进行插入,则首先不会出现此问题。
如果您从客户处获得Excel文件,则需要验证Excel工作表中的日期值是否有效。
如果没有,有人需要更正Excel文件中的数据。
如果使用access + SQL Server,则最小日期值必须是两个最小日期值的最大值,最大日期值必须是两个最大日期值中的最小值。