在SQL Server的内部存储中,日期和时间不是以字符串的形式存储的,而是使用整数来存储的。使用特定的格式来区分日期部分和时间部分的偏移量,并通过基准日期和基准时间来还原真实的数据。

一,DateTime的内部存储

SQL Server存储引擎把DateTime类型存储为2个int32类型,共8个字节,第一个int32 整数(前4个字节)存储的是日期相对于基准日期(1900-01-01)的偏移量。基准日期是1900-01-01,当前4 字节为0 时,表示的日期是1900 年1 月1 日。第二个int32整数(后4个字节)存储的是午夜(00:00:00.000)之后的时钟滴答数,每个滴答为1⁄300秒,精确度为3.33毫秒(0.00333秒,3.33ms),因此,DateTime能够表示的时间,可能会存在一个滴答的时间误差。

DateTime的内部存储格式,用十六进制表示是:DDDDTTTT

  • DDDD:占用2个字节,表示对基准日期的偏移量
  • TTTT:占用两个字节,表示对午夜之后的始终滴答数

举个例子,对于如下的日期和时间,把DateTime类型转换为大小为8个字节的16进制,每两个数字对应1个字节:

declare @dt datetime = '2015-05-07 10:05:23.187'select convert(varbinary(8), @dt) as date_time_binary--output 0x0000A49100A6463C

把时间的二进制格式中的字节拆分成两部分:前4个字节表示date,后4个字节表示time,得出的结果如下:

declare @dt datetime = '2015-05-07 10:05:23.187'select substring(convert(varbinary(8), @dt), 1, 4) as date_binary, cast(substring(convert(varbinary(8), @dt), 1, 4) as int) as date_int, substring(convert(varbinary(8), @dt), 5, 4) as time_binary, cast(substring(convert(varbinary(8), @dt), 5, 4) as int) as time_int;

通过基准时间和偏移量,把整数还原为原始的日期和时间:

declare @Time time='00:00:00.000'declare @Date date='1900-01-01'select dateadd(day, 42129, @Date) as originl_date , dateadd(ms,10896956*10/3, @Time) as original_time

DateTime2(n)数据类型存储日期和时间,它是DateTime的升级版本,由于小数秒n的精度可以自主设置,其存储大小(Storage Size)不固定,DateTime2(n)占用的存储空间和小数秒的精度之间的关系是:

  • DateTime2(n)内部存储的第一个字节存储精度n,后续的字节用于存储日期和时间的值。
  • 当小数秒的精度 n < 3 时,总的存储空间是1B(精度)+6 B(数据);
  • 当小数秒的精度 n 是 3 - 4 时,总的存储空间是1B(精度)+ 7B(数据);
  • 当小数秒的精度 n 是 5 - 7 时,总的存储空间是1B(精度)+ 8B(数据),最大的小数秒精度是7,默认值是7;

1,二进制逆序

在探索DateTime2(n)的内部存储之前,先了解一下字节存储的“小端”格式和“大端”格式:

  • 大端格式:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
  • 小端格式:是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。

举个例子,假如内存地址左边是地位,右边是高位,对于数字275,使用两个字节来存储:

  • 如果采用大端格式:字节序列是0x0113
  • 如果采用小端格式:字节序列是0x1301

DateTime2(n)的内部存储格式使用的是小端格式,这种格式适合CPU的运算。

2,DateTime2的存储格式

DateTime2(n)的内部存储格式是:

  • 第一字节存储的精度n,
  • 后三个字节记录从基准日期0001-01-01之后的多少天,采用小端格式。
  • 中间余下的字节记录子夜之后经过的时间单位间隔(time unit interval,TUI)的数量,采用小端格式。

TUI是由精度来控制的,每一个TUI是10的n次方之一秒,也就是:

  • 对于 DateTime2(7),TUI是100ns;
  • 对于 DateTime2(6),TUI是1微秒(=1000ns);
  • 对于 DateTime2(5),TUI是10微秒;
  • 对于 DateTime2(4),TUI是100微秒;
  • 对于 DateTime2(3),TUI是1ms(1毫秒=1000微秒);

为了便于运算,把DateTime2(n) 的字节流逆序排列:前3个字节表示的是天数,最后一个字节表示的是精度,中间余下的字节表示的TUI的数量。例如,对于 DateTime2(7)按照字节流逆序处理之后,存储空间是9个字节:前三个字节是存储的从基准日期0001-01-01之后的多少天,最后一位是精度n,中间的5个字节表示从子夜开始有多少个TUI。

2,把DateTime2转换为二进制存储

把DateTime2转换为二进制存储,并作逆序处理,DateTime2(3)的精度为3,存储空间是8个字节,后三个字节记录从基准日期0001-01-01之后的多少天,前3个字节表示从子夜开始有多少个TUI。

declare @dt datetime2(3)='2015-05-07 10:05:23.187'declare @dt_bi varbinary(max)=convert(varbinary(max), @dt) select @dt_bi as date_time_binary ,convert(varbinary(max),reverse(@dt_bi)) as reverse_binary
declare @dt datetime2(3)='2015-05-07 10:05:23.187'declare @dt_bi varbinary(max)=convert(varbinary(max), @dt) declare @dt_bi_littleEnd varbinary(max)select @dt_bi_littleEnd=convert(varbinary(max),reverse(@dt_bi))select substring(convert(varbinary(8), @dt_bi_littleEnd), 1, 3) as date_binary, cast(substring(convert(varbinary(8), @dt_bi_littleEnd), 1, 3) as int) as date_int, substring(convert(varbinary(8), @dt_bi_littleEnd), 4, 4) as time_binary, cast(substring(convert(varbinary(8), @dt_bi_littleEnd), 4, 4) as int) as time_int, substring(convert(varbinary(8), @dt_bi_littleEnd), 8, 1) as precision_binary, cast(substring(convert(varbinary(8), @dt_bi_littleEnd), 8, 1) as int) as precision_int;

有了偏移量,就可以在基准日期和时间之上加上偏移量来获得原始值:

declare @Time time='00:00:00.000'declare @Date date='0001-01-01'select dateadd(day, 735724, @Date) as originl_date , dateadd(ms,36323187, @Time) as original_time

What is the SQL Server 2008 DateTime2 Internal Structure?

How to Get SQL Server Dates and Times Horribly Wrong

总结

更多相关文章

  1. Android(安卓)Calendar使用过程中遇到的问题
  2. DatePicker 日期选择控件 DatePickerDialog 日期选择对话框
  3. android 日期对话框
  4. android calendar的使用
  5. ch07 Android(安卓)日期与时间对话框
  6. ch07 Android(安卓)日期与时间对话框
  7. Android时间工具类 本地转UTC,UTC转本地
  8. Android中实现日期时间选择器(DatePicker和TimePicker)
  9. Android中日期和时间控件的使用

随机推荐

  1. 【开发者必看】移动应用趋势洞察白皮书-
  2. RocketMQ 部署启动指南-Docker 版
  3. SPI 机制-插件化扩展功能
  4. 锁住余额,为何还会更新异常?
  5. Spring 注解编程之模式注解
  6. 分享一些 Windows 平台上的神器
  7. 缘起 Dubbo ,讲讲 Spring XML Schema 扩展
  8. 聊聊对账系统的设计方案
  9. 还不知道如何使用 IDEA ?教你三招快速掌握
  10. 聊聊如何从零开始自学编程