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。
- 值 0 和 1 “向下舍入”为 0。
- 值 2、3 和 4 “向下舍入”为 3。
- 值 5、6、7 和 8 “向下舍入”为 7。
- 值 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 a
smalldatetime value of
1 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 。