5

考虑以下程序:

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

对我来说奇怪的是 0.464737 被四舍五入为 0.463。那不应该四舍五入到0.464吗?

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

为什么它会变成它所做的? 以及如何让客户端舍入来完成 SqlServer 将要做的事情?

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

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

4

3 回答 3

8

SQL Server DATETIME has an accuracy of 3.33ms - therefore, you cannot get all possible values, and there's a good chance .464 was just such a value.

On SQL Server 2008, you could use DATETIME2 or TIME(x) datatypes which have an accuracy to 100ns - that should be plenty enough for "regular" use

于 2011-10-19T16:37:27.983 回答
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 向上舍入到THE NEXT DAY。因此,“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'

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

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

我想说,如果精度对您很重要,请将您的日期/时间值作为ISO 8601格式的字符串存储在 SQL Server 中,类似于2011-10-30T23:59:55.1234(或等效的“紧凑”形式 ( 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 ,
  ...
)

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

于 2011-10-19T17:22:45.160 回答
1

SqlDateTime 结构

表示日期和时间数据,取值范围从 1753 年 1 月 1 日到 9999 年 12 月 31 日,精度为 3.33 毫秒,要存储在数据库中或从数据库中检索。SqlDateTime 结构具有与其对应的 .NET Framework 类型 DateTime 不同的底层数据结构,它可以表示 12:00: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 值类型表示日期和时间,其值范围从 0001 年 1 月 1 日午夜 12:00:00 到公元 9999 年 12 月 31 日晚上 11:59:59

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

时间值以 100 纳秒为单位,称为滴答声,特定日期是公历中自 0001 年 1 月 1 日午夜 12:00 以来的滴答声数(不包括闰秒添加的滴答声) . 例如,刻度值 31241376000000000L 表示日期,即 0100 年 1 月 1 日星期五午夜 12:00:00。DateTime 值始终在显式或默认日历的上下文中表示。

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

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

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

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

这也在 3.33 毫秒的精度范围内...如果您需要比 3.33 毫秒更准确的东西,那么您将不得不使用 SQL Server 2008

于 2011-10-19T16:49:52.577 回答