SqlDateTime如何进行精度降低

Vac*_*ano 5 c# sqldatetime

考虑以下程序:

DateTime dateTime = new DateTime(634546165144647370);
SqlDateTime sqlDateTime = new SqlDateTime(dateTime);

Console.WriteLine("dateTime.TimeOfDay    = " + dateTime.TimeOfDay);
Console.WriteLine("sqlDateTime.TimeOfDay = " + sqlDateTime.Value.TimeOfDay);
Console.ReadLine();
Run Code Online (Sandbox Code Playgroud)

这将有以下输出:

dateTime.TimeOfDay    = 10:21:54.4647370  
sqlDateTime.TimeOfDay = 10:21:54.4630000
Run Code Online (Sandbox Code Playgroud)

对我来说奇怪的是.464737被舍入为.463.不应该四舍五入到.464吗?

我假设我没有在.NET代码中发现错误,所以问题是:

为什么它要做到这一点呢? 以及如何进行客户端舍入以完成SqlServer将要执行的操作?

作为旁注,我将这个日期时间保存到SQL Server数据库(在DateTime列中)并再次将其拉出来,结果为10:21:54.4670000.所以我真的很困惑.(我认为SqlDateTime会与SQL Server要做的事情相匹配.)

注意:因为我使用的是OData,所以我无法在SQL Server中使用DateTime2.

mar*_*c_s 8

SQL Server DATETIME的准确度为3.33ms - 因此,您无法获得所有可能的值,并且很有可能.464只是这样的值.

在SQL Server 2008中,你可以使用DATETIME2TIME(x)具有精度为100ns数据类型-这应该是足够足够了"常规"使用


Nic*_*rey 6

SQL Server的datetype数据类型在内部是两个32位字(整数).高位字是自SQL Server使用的内部日历的纪元(零点)以来的天数偏移:该纪元是1900年1月1日00:00:00.000.低位字是自开始日(00:00:00.000 /午夜)以来的毫秒数偏移量.

由于历史原因,低阶字的精度为1毫秒; 精度是1/300秒(!?).这意味着任何给定的时间点都会四舍五入为0,3或7毫秒的增量.

要按照SQL Server执行的方式进行转换,请执行以下操作:将正在考虑的实际时间的毫秒部分取为0-999,模数为100的值.这将为您提供低位数字,即0-9.因此,如果当前时间是23:57:23.559,毫秒组件是559.模数100你得到9.

  1. 值0和1"向下舍入"为0.
  2. 值2,3和4被"向下舍入"到"3".
  3. 值5,6,7和8被"向下舍入"到7.
  4. 值9被向上舍入为0.这具有相当令人不愉快和令人讨厌的副作用:如果时间的毫秒部分是999,则其上升1毫秒.这意味着时间23:59:59.999向上舍入到下一天.因此,'2010年12月31日23:59:59.999'的转换产生的日期时间值为... 2011年1月1日00:00:00.000.

辉煌!或者其他的东西.

请参阅SQL Server 2005 BOL下的"备注"部分:http://msdn.microsoft.com/en-us/library/ms187819( v = SQL.90).aspx

所有这一切的结果是你无法对日期范围/时间段进行明显的检查......就像这样

where myDateColumn between '1 September 2011 00:00:00.000'
  and '30 September 2011 23:59:59.999'
Run Code Online (Sandbox Code Playgroud)

因为这可能会带来下一个时期的[小]数据.你不能说

where myDateColumn between '1 September 2011 00:00'
  and '30 September 2011 23:59:59'
Run Code Online (Sandbox Code Playgroud)

因为这可能会排除属于该时期的数据.相反,你必须说出类似的话

  • where myDateColumn >= '1 September 2011 00:00:00.000' and myDateColumn < '1 October 2011 00:00:00.000', 要么

  • where myDateColumn >= '1 September 2011 00:00:00.000' and myDateColumn <= '30 September 2011 23:59:59.997'

应该注意的是smalldatetime,具有1分钟的精度,表现出相同的虚假行为:如果所考虑的时间的秒分量是29.998秒或更小,则向下舍入到最接近的分钟; 如果是29.999或更高,它会向上舍入到下一分钟,因此值31 Dec 2010 23:59:30.000' winds up as asmalldatetime value of2011年1月1日00:00:00`.

这具有各种影响,尤其是对计费系统的WRT等.

我会说,如果精度对你很重要,可以将你的日期/时间值存储在SQL Server中,作为ISO 8601格式的字符串,类似2011-10-30T23:59:55.1234(或等效的'compact'形式(20111030T235955.1234).ISO 8601正确整理和比较;它很容易转换并且它是人类可读的.更好的是将它分成两列 - 一个用于date(2011-10-30),一个用于time(23:59:55.1234).然后添加第三个计算列将它们放在一起:

create table foo
(
  ...
  transaction_date char(10) not null ,
  transaction_time char(12) not null ,
  ...
  iso8601_transaction_datetime as transaction_date + 'T' + transaction_time ,
  ...
)
Run Code Online (Sandbox Code Playgroud)

ISO 8601的一个很好的总结是在http://www.cl.cam.ac.uk/~mgk25/iso-time.html.维基百科也有很好的信息:http://en.wikipedia.org/wiki/ISO_8601.