在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

1,拆分出date和time

把时间的二进制格式中的字节拆分成两部分:前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;

 2,通过偏移量还原日期和时间

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

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的内部存储

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

把二进制值拆分成DateTime2(3)的各个组成成分:

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;

3,利用偏移量和基准还原原始值

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

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

深入SQL Server 日期和时间的内部存储的更多相关文章

  1. SQL Server日期和时间的格式

    在SQL Server数据库中,SQL Server日期时间格式转换字符串可以改变SQL Server日期和时间的格式,是每个SQL数据库用户都应该掌握的.本文我们主要就介绍一下SQL Server日 ...

  2. SQL Server 日期和时间类型

    在Microsoft SQL Server的类型系统中,使用 date 表示日期类型,使用time表示时间类型,使用DateTime和DateTime2表示日期和时间的组合,DateTime2是Dat ...

  3. SQL Server 日期和时间函数

    http://www.cnblogs.com/adandelion/archive/2006/11/08/554312.html 1.常用日期方法(下面的GetDate() = '2006-11-08 ...

  4. [Irving]Sql Server 日期、时间、比较

    在sql 的数据库表里时间字段是比较全的格式:例如GetdataTime字段:2007-06-05 12:34:50. 但在前台程序里,利用日历控件,可能查询的时候是以某天来做比较,例如开始时间:20 ...

  5. 【SQL SERVER重新认识】数据内部存储结构简单探索

    数据库经常需要打交道,但是从来没想过数据库内部是如何存储数据. 今天探索一下数据库内部如何存储数据,从下面几个方面探索 数据库内部如何存储数据 索引数据如何存储 操作数据对存储影响 总结 数据库内部如 ...

  6. SQL Server日期时间格式转换字符串详解 (详询请加qq:2085920154)

    在SQL Server数据库中,SQL Server日期时间格式转换字符串可以改变SQL Server日期和时间的格式,是每个SQL数据库用户都应该掌握的.本文我们主要就介绍一下SQL Server日 ...

  7. SQL Server日期时间格式转换字符串

    在SQL Server数据库中,SQL Server日期时间格式转换字符串可以改变SQL Server日期和时间的格式,是每个SQL数据库用户都应该掌握的.本文我们主要就介绍一下SQL Server日 ...

  8. SQL Server日期时间格式转换字符串详解

    本文我们主要介绍了SQL Server日期时间格式转换字符串的相关知识,并给出了大量实例对其各个参数进行对比说明,希望能够对您有所帮助. 在SQL Server数据库中,SQL Server日期时间格 ...

  9. sql server 日期

    在SQL Server数据库中,SQL Server日期时间格式转换字符串可以改变SQL Server日期和时间的格式,是每个SQL数据库用户都应该掌握的.本文我们主要就介绍一下SQL Server日 ...

随机推荐

  1. 持续集成学习6 jenkins自动化代码构建

    一.实验目标 二.配置 1.配置mvn构建 [root@node1 ~]# wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3 ...

  2. Android_Fragment

    (一) Faragment有自己的生命周期 Fragment依赖于Activity Fragmen通过getActivity()可以获取所在Activity:Activity通过FragmentMan ...

  3. [考试反思]1023csp-s模拟测试84:精妙

    一套很奇怪的题.单调性+神仙dp/搜索+随机化. 但是说实在的,思路都很不错. 考场上显然乱搞没什么好说的. 虽说T2剪枝打错变量名掉了20分... T1:Smooth 暴力各有不同,最暴力的想法就是 ...

  4. jq实现多选框及反选

    1 效果图 2 html <div class="main"> <table> <tr> <th><input type=&q ...

  5. java应用性能调优之详解System的gc垃圾回收方法

    一.什么是System.gc()? System.gc()是用Java,C#和许多其他流行的高级编程语言提供的API.当它被调用时,它将尽最大努力从内存中清除垃圾(即未被引用的对象).名词解释:GC, ...

  6. 最近的项目系列1——core整合SPA

    1.前言 当前,前后端分离大行其道,我本人之前不少项目也是纯前后端分离,但总有些场景,春前后端分离整起来比较痛苦,比如我手头这个公众号项目吧,它涉及到第三方鉴权,第三方凭证,以及微信凭证这些,都不适合 ...

  7. .NET Core3.0 EF 连接 MySql

    一:创建项目 添加 csproj (或者直接NuGet 引用) <ItemGroup> <PackageReference Include="Microsoft.Entit ...

  8. MyBatis批量更新动态sql

    <update id="updateDataKetState"> update ${tablespace}.IDEA_DATAKEY_STATE <trim pr ...

  9. [笔记] HOW2J.CN网站记录的java笔记_第四部分_HTML

    1.写一个显示Hello World的网页, <html> <body> <p>Hello World</p> </body> </h ...

  10. [git]关于github的一些用法笔记(入门)

    本视频来自于观看尚硅谷B站教学:https://www.bilibili.com/video/av10475153?from=search&seid=9735863941344749813 而 ...