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

时间:2013-11-21 22:24:37

标签: c# sql ms-access datetime

我有一些从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读取同一行时抛出例外。

2 个答案:

答案 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文件中的数据。

  • 日期必须始终采用相同的格式(MM-DD-YYYY),有时可能不是(dd.MM.yyyy)
  • 日期必须是>最小值,如SQL-Server中的01.01.1753(由于MM-DD-YY格式的日期特别重要)
  • 日期不得超过31.12.9999 23:59:59.995 in SQL-Server

如果使用access + SQL Server,则最小日期值必须是两个最小日期值的最大值,最大日期值必须是两个最大日期值中的最小值。