在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. 快速学习ggplot2

    R语言里面一个比较重要的绘图包——ggplot2,是由Hadley Wickham于2005年创建,于2012年四月进行了重大更新,作者目前的工作是重写代码,简化语法,方便用户开发和使用.ggplot ...

  2. windows服务参考

    dll文件 aaclient.dll 何时何地都可以访问客户端 accessibilitycpl.dll 轻松访问控制面板 acledit.dll 访问控制列表编辑器 aclui.dll 安全描述符编 ...

  3. SpringBoot正确打日志的姿势

    前篇 Spring Boot 日志处理你还在用Logback? 本文简介 前篇侧重 Log4j2 的配置,本篇侧重统一日志处理的应用,以下包含 HTTP 请求的日志处理.Exception 异常日志处 ...

  4. Pandas 分组聚合

    # 导入相关库 import numpy as np import pandas as pd 创建数据 index = pd.Index(data=["Tom", "Bo ...

  5. 那些Java架构师必知必会的技术

    Java基础 Java 7 和 Java 8 中的 HashMap原理解析 Java7 和 Java8 中的 ConcurrentHashMap 原理解析 Java中自定义注解 Java函数式编程和l ...

  6. UiPath之文件操作

    今天给大家介绍一下,在UiPath中如何操作文件,比如需要在某个文件夹中自动创建一个当天日期的文本. 主要使用的activity有: l  Assign l  Path Exists l  If l  ...

  7. Go 基础学习笔记 (5)| 数据类型说明与使用

    在 Go 编程语言中,数据类型用于声明函数和变量. 数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存. Go 语言按类别有以下几种 ...

  8. python——inspect模块

    inspect模块常用功能 import inspect # 导入inspect模块 inspect.isfunction(fn) # 检测fn是不是函数 inspect.isgenerator((x ...

  9. django 之创建自己的模板(使用案例)

    Django 创建自己的模板篇(实例) 此处需要创建模板,主要是对自己的模板进行扩展: 一般是扩展模板的tag和filter两个功能.可以用来创建你自己的tag和filter功能库. 创建模板库 分为 ...

  10. SQlALchemy session详解

    系列文章: Python SQLAlchemy入门教程 概念 session用于创建程序和数据库之间的会话,所有对象的载入和保存都需通过session对象 . 通过sessionmaker调用创建一个 ...