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(); 

这将有以下输出:

 dateTime.TimeOfDay = 10:21:54.4647370 sqlDateTime.TimeOfDay = 10:21:54.4630000 

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

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

为什么它完成了它的作用? 以及如何进行客户端舍入以完成SqlServer将要执行的操作?

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

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

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

在SQL Server 2008上,您可以使用精度为100ns的DATETIME2TIME(x)数据类型 – 这应该足够“常规”使用

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' 

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

 where myDateColumn between '1 September 2011 00:00' and '30 September 2011 23:59:59' 

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

  • 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'

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

这具有各种含义,尤其是对计费系统等的WRT。

我会说,如果精度对您很重要,请将您的日期/时间值作为ISO 8601格式的字符串存储在SQL Server中,如2011-10-30T23:59:55.1234 (或等效的'compact'forms( 20111030T235955.1234 ISO 8601正确地进行整理和比较;它易于转换并且是人类可读的。甚至更好地将其分成两列 - 一列用于日期( 2011-10-30 ),一列用于时间( 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 , ... ) 

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

SqlDateTime结构

表示从1753年1月1日到9999年12月31日的值的日期和时间数据,以及存储在数据库中或从数据库中检索的3.33毫秒的准确度。 SqlDateTime结构与其对应的.NET Framework类型DateTime具有不同的基础数据结构,可以表示在12:00到AM 1/1/0001和11:59:59 PM 12/31/9999之间的任何时间到精度为100纳秒。 SqlDateTime实际上存储了相对差异到00:00:00 AM 1/1/1900。 因此,从“00:00:00 AM 1/1/1900”到整数的转换将返回0。

我认为sqlDateTime的准确度在3.33毫秒之内。

DateTime值类型表示日期和时间,其值范围为公元9999年12月31日晚上1月1日午夜,1:00 Anno Domini(Common Era)到11:59:59 PM

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

时间值以称为刻度的100纳秒单位进行测量,特定日期是格里高利历日历中自公元0001年1月1日午夜12点起的刻度数(不包括闰秒添加的刻度) 。 例如,刻度值31241376000000000L表示日期,星期五,1月01日,0100 12:00:00午夜。 DateTime值始终在显式或默认日历的上下文中表示。

在内部,所有DateTime值都表示为自0001年1月1日午夜12:00:00起经过的刻度数(100纳秒间隔的数量)。实际的DateTime值与该值的方式无关出现在用户界面元素中或写入文件时出现。 DateTime值的出现是格式化操作的结果。 格式化是将值转换为字符串表示的过程。

由于日期和时间值的出现取决于诸如文化,国际标准,应用程序要求和个人偏好等因素,因此DateTime结构通过其ToString方法的重载在格式化日期和时间值方面提供了极大的灵活性。 默认的DateTime.ToString()方法使用当前区域性的短日期和长时间模式返回日期和时间值的字符串表示forms。 以下示例使用默认的DateTime.ToString()方法,使用en-US文化的短日期和长时间模式显示日期和时间,en-US文化是运行该示例的计算机上的当前文化。

看起来DateTime在100ns内是准确的,这与您经历的差异有关。

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

这也是3.33毫秒内的准确度…如果你需要更精确的东西然后3.33毫秒,那么你将不得不使用SQL Server 2008