一尘不染

Access ODBC驱动程序中无效的日期时间格式异常

sql

我有一些从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以十进制为

41275.9999999999417923390865326

同样可能引起关注的是,尽管该值在尝试通过an读取行时导致错误OdbcConnection,但使用an读取同一行OleDbConnection
没有 引发异常。


阅读 222

收藏
2021-03-08

共1个答案

一尘不染

考虑到更新后的问题中的测试数据,以下变通办法似乎可以正常工作。它检查.Driver打开的连接的属性,以查看它是否正在从Access数据库中读取。如果是这样,它将获取Date/Timeas的值Double,然后将其转换回System.DateTime。否则,它将仅从datetimeSQL
Server正常检索。

(请注意,此特定方法使用`rdr[0]) * 86400`''对于Access中早于的值(即,当值为负时) **将无法** 正常工作。)`Date/Time1899-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();
        }
    }
}
2021-03-08