传递给存储过程的日期参数未按预期工作

时间:2013-09-06 17:57:27

标签: c# sql-server

我在项目中遇到了一个问题,我将日期作为09/03/2013 23:59:59传递给存储过程,但在profiler .net中将其转换为09/04/2013 00:00:00

确认我创建了一个小型测试应用程序(任何人都可以使用它进行复制,我使用.Net 4.5和Sql server 2012快速版)。

以下是测试代码:

DateTime startdate = DateTime.Parse("09/03/2013");
DateTime endDate = startdate.AddDays(1).AddTicks(-1);
        try
        {
            using (SqlConnection konekcija = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
            {

                konekcija.Open();

                using (SqlCommand cmd = new SqlCommand())
                {
                    cmd.Connection = konekcija;

                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.CommandText = "[Interface].[uspTestDateParameter]";

                    cmd.Parameters.AddWithValue("@CurrentDate", startdate);
                    cmd.Parameters.AddWithValue("@BatchEndDate", endDate);
                    using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                    {
                        // Fill the DataSet using default values for DataTable names, etc
                        DataSet dataset = new DataSet();
                        da.Fill(dataset);
                        DataTable dt = dataset.Tables[0];
                        //return dataset;
                    }
                }
            }
        }
        catch (Exception ee)
        {

        }

以下是程序:

CREATE PROCEDURE [Interface].[uspTestDateParameter]
(
@CurrentDate DateTime
,@BatchEndDate DateTime
) 
AS
BEGIN
Declare @table table (strt Datetime ,endT Datetime )

Insert into @table values (@CurrentDate,@BatchEndDate)

Select * from @table
END

返回的结果集为9/3/2013 12:00:00 AM 9/4/2013 12:00:00 AM

我可以附加数据集可视化器的屏幕截图,但不能这样做,因为它需要声誉10.但上面是我得到的两列(strt,enDt)的值。

有人可以帮忙吗?由于这个原因,我的生产过程失败了。

3 个答案:

答案 0 :(得分:4)

DATETIME如下所述四舍五入:

http://technet.microsoft.com/en-us/library/ms187819.aspx

本文明确规定所有值均为.000,.003或.007秒。用户指定的DateTime 01/01/98 23:59:59.999将始终存储为1998-01-02 00:00:00.000

不是使用刻度线,为什么不能执行以下操作?

DateTime endDate = startdate.AddDays(1).AddSeconds(-1);

这会实际传递你说过的日期(09/03/2013 23:59:59)而不是下一秒的一个标记。

或者,使用DATETIME2作为SQL数据类型,根据文档,它的准确度为100ns(一个刻度):

http://technet.microsoft.com/en-us/library/bb677335.aspx

答案 1 :(得分:1)

问题在于如AntP所描述的那样舍入SQL Server datetime类型。

您可以考虑两种不同的解决方案:

选项#1

在Tim建议的SQL Server中使用datetime2类型。它具有更高的精度,因此您不可能圆。这仍然很棘手,因为你必须知道你发送了多少精度以及这种类型将支持多少。换句话说,它应该是23:59:59.999还是23:59:59.99999923:59:59.0就足够了?您必须决定对您的申请有何意义。

如果您的数据始终包含整个日期,则可以将输入值更改为:

DateTime endDate = startdate.AddDays(1).AddSeconds(-1);

即使使用datetime类型,也不会进行舍入。

选项#2

使用[start,end)的半开区间范围。当结束日期是独占的时,您的查询会更简单,您不必担心精确度。当两个间隔相互交叉时,一个间隔的结束将与下一个间隔的开始完全相同。从来没有任何歧义,因为结束日期是独家的。

您可以将09/03/2013 00:00:00作为09/03/2013 23:59:59发送至09/03/2013 00:00:00,而不是将范围作为09/04/2013 00:00:00发送至StartOfRange <= @TheDate < EndOfRange ,而应了解已排除确切的结束日期。

换句话说,日期在以下范围内:

StartOfRange <= @TheDate AND EndOfRange > @TheDate

或换句话说:

{{1}}

在.NET方面,您仍然可以将输入术语视为完全包容。只需在将结果值传递给SQL之前将其添加到最终值。例如,如果您要求将整个日期作为输入,则将一整天添加到结束日期。

答案 2 :(得分:0)

Tick是一个非常小的时间单位(MSDN)。一毫秒内有10,000个滴答。

尝试减去1-2秒以查看它是否有效。

顺便说一句,SQL Server的datetime只能存储333毫秒(例如:.000,.003。,。006等)