热门标签 | HotTags
当前位置:  开发笔记 > 数据库 > 正文

SQLServer日期和时间的内部存储过程

在SQLServer的内部存储中,日期和时间不是以字符串的形式存储的,而是使用整数来存储的。这篇文章主要介绍了SQLServer日期和时间的内部存储,需要的朋友可以参考下

在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&#63;

How to Get SQL Server Dates and Times Horribly Wrong

总结

以上所述是小编给大家介绍的SQL Server 日期和时间的内部存储,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!


推荐阅读
  • 本文详细介绍了如何使用libpq库与PostgreSQL后端建立连接。通过探讨PQconnectdb()函数的工作原理及其在实际应用中的使用方法,帮助读者理解并掌握建立高效、稳定的数据库连接的关键步骤。 ... [详细]
  • Windows服务与数据库交互问题解析
    本文探讨了在Windows 10(64位)环境下开发的Windows服务,旨在定期向本地MS SQL Server (v.11)插入记录。尽管服务已成功安装并运行,但记录并未正确插入。我们将详细分析可能的原因及解决方案。 ... [详细]
  • 数据库内核开发入门 | 搭建研发环境的初步指南
    本课程将带你从零开始,逐步掌握数据库内核开发的基础知识和实践技能,重点介绍如何搭建OceanBase的开发环境。 ... [详细]
  • 本文深入探讨 MyBatis 中动态 SQL 的使用方法,包括 if/where、trim 自定义字符串截取规则、choose 分支选择、封装查询和修改条件的 where/set 标签、批量处理的 foreach 标签以及内置参数和 bind 的用法。 ... [详细]
  • 使用C#开发SQL Server存储过程的指南
    本文介绍如何利用C#在SQL Server中创建存储过程,涵盖背景、步骤和应用场景,旨在帮助开发者更好地理解和应用这一技术。 ... [详细]
  • 本文探讨了适用于Spring Boot应用程序的Web版SQL管理工具,这些工具不仅支持H2数据库,还能够处理MySQL和Oracle等主流数据库的表结构修改。 ... [详细]
  • 本文详细介绍了如何通过多种编程语言(如PHP、JSP)实现网站与MySQL数据库的连接,包括创建数据库、表的基本操作,以及数据的读取和写入方法。 ... [详细]
  • 在当前众多持久层框架中,MyBatis(前身为iBatis)凭借其轻量级、易用性和对SQL的直接支持,成为许多开发者的首选。本文将详细探讨MyBatis的核心概念、设计理念及其优势。 ... [详细]
  • 在使用 DataGridView 时,如果在当前单元格中输入内容但光标未移开,点击保存按钮后,输入的内容可能无法保存。只有当光标离开单元格后,才能成功保存数据。本文将探讨如何通过调用 DataGridView 的内置方法解决此问题。 ... [详细]
  • 本文详细介绍了如何在 Linux 平台上安装和配置 PostgreSQL 数据库。通过访问官方资源并遵循特定的操作步骤,用户可以在不同发行版(如 Ubuntu 和 Red Hat)上顺利完成 PostgreSQL 的安装。 ... [详细]
  • 如何在PostgreSQL中查看数据表
    本文将指导您使用pgAdmin工具连接到PostgreSQL数据库,并展示如何浏览和查找其中的数据表。通过简单的步骤,您可以轻松访问所需的表结构和数据。 ... [详细]
  • 利用存储过程构建年度日历表的详细指南
    本文将介绍如何使用SQL存储过程创建一个完整的年度日历表。通过实例演示,帮助读者掌握存储过程的应用技巧,并提供详细的代码解析和执行步骤。 ... [详细]
  • 本文介绍了如何通过 Maven 依赖引入 SQLiteJDBC 和 HikariCP 包,从而在 Java 应用中高效地连接和操作 SQLite 数据库。文章提供了详细的代码示例,并解释了每个步骤的实现细节。 ... [详细]
  • 在使用SQL Server进行动态SQL查询时,如果遇到LIKE语句无法正确返回预期结果的情况,通常是因为参数传递方式不当。本文将详细探讨这一问题,并提供解决方案及相关的技术背景。 ... [详细]
  • 本文介绍如何通过创建替代插入触发器,使对视图的插入操作能够正确更新相关的基本表。涉及的表包括:飞机(Aircraft)、员工(Employee)和认证(Certification)。 ... [详细]
author-avatar
鸿少爷仰望星空
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有