我在项目中遇到了一个问题,我将日期作为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)的值。
有人可以帮忙吗?由于这个原因,我的生产过程失败了。
答案 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(一个刻度):
答案 1 :(得分:1)
问题在于如AntP所描述的那样舍入SQL Server datetime
类型。
您可以考虑两种不同的解决方案:
选项#1
在Tim建议的SQL Server中使用datetime2
类型。它具有更高的精度,因此您不可能圆。这仍然很棘手,因为你必须知道你发送了多少精度以及这种类型将支持多少。换句话说,它应该是23:59:59.999
还是23:59:59.999999
或23: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等)