博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
解剖SQLSERVER 第四篇 OrcaMDF里对dates类型数据的解析(译)
阅读量:6002 次
发布时间:2019-06-20

本文共 5312 字,大约阅读时间需要 17 分钟。

原文:

解剖SQLSERVER 第四篇  OrcaMDF里对dates类型数据的解析(译)

在SQLSERVER里面有几种不同的date相关类型,当前OrcaMDF 支持三种最常用的date类型:date,datetime,smalldatetime

 

SqlDate实现

date 类型在三种类型之中是最简单的,他是一个3个字节的定长类型,存储了日期值它支持的日期范围从0001-01-01到9999-12-31

默认值是1900-01-01

比较坑爹的是.NET里面还没有任何标准实现能够支持3个字节的整数类型,只有short类型和int类型,但是,他们要不太大要不太小

另外,要正确读取日期值,对于.NET的4字节整型我们必须执行一些转变去获取正确的数字

一旦我们获取到date的值,我们可以创建一个默认的datetime类型并且添加天数进去

public class SqlDate : ISqlType{    public bool IsVariableLength    {        get { return false; }    }    public short? FixedLength    {        get { return 3; }    }    public object GetValue(byte[] value)    {        if (value.Length != 3)            throw new ArgumentException("Invalid value length: " + value.Length);        // Magic needed to read a 3 byte integer into .NET's 4 byte representation.        // Reading backwards due to assumed little endianness.        int date = (value[2] << 16) + (value[1] << 8) + value[0];        return new DateTime(1, 1, 1).AddDays(date);    }}

相关测试

using System;using NUnit.Framework;using OrcaMDF.Core.Engine.SqlTypes;namespace OrcaMDF.Core.Tests.Engine.SqlTypes{    [TestFixture]public class SqlDateTests{        [Test]public void GetValue(){var type = new SqlDate();var input = new byte[] { 0xf6, 0x4c, 0x0b };Assert.AreEqual(new DateTime(2028, 09, 09), Convert.ToDateTime(type.GetValue(input)));input = new byte[] { 0x71, 0x5c, 0x0b };Assert.AreEqual(new DateTime(2039, 07, 17), Convert.ToDateTime(type.GetValue(input)));}        [Test]public void Length(){var type = new SqlDate();Assert.Throws
(() => type.GetValue(new byte[2]));Assert.Throws
(() => type.GetValue(new byte[4]));}}}

 

SqlDateTime实现

date类型只能存储日期,而datetime类型不但能存储date也能存储time

datetime存储8字节定长数据值,第一部分是time(4字节),而第二部分是date(4字节)

计算date部分跟上面介绍date类型基本上一样,不过这一次date部分是一个四字节整数,比上面的例子容易处理多了,上面的date类型是3个字节

time部分存储为自午夜时的ticks数,一个tick就是1/300th 秒,为了显示tick值,我们首先定义一个常量,常量值是10d/3d

time的各个部分实际同样存储在同一个整型值里面(比如时间,分钟,秒,毫秒),所以我们要独立访问这些单独的部分,我们必须

要执行一些转换 (包括取模和相除)

部分     计算小时   X / 300 / 60 / 60分钟   X / 300 / 60 % 60秒     X / 300 % 60毫秒   X % 300 * 10d / 3d
public class SqlDateTime : ISqlType{    private const double CLOCK_TICK_MS = 10d/3d;    public bool IsVariableLength    {        get { return false; }    }    public short? FixedLength    {        get { return 8; }    }    public object GetValue(byte[] value)    {        if (value.Length != 8)            throw new ArgumentException("Invalid value length: " + value.Length);        int time = BitConverter.ToInt32(value, 0);        int date = BitConverter.ToInt32(value, 4);        return new DateTime(1900, 1, 1, time/300/60/60, time/300/60%60, time/300%60, (int)Math.Round(time%300*CLOCK_TICK_MS)).AddDays(date);    }}

相关测试

using System;using NUnit.Framework;using OrcaMDF.Core.Engine.SqlTypes;namespace OrcaMDF.Core.Tests.Engine.SqlTypes{    [TestFixture]public class SqlDateTimeTests{        [Test]public void GetValue(){var type = new SqlDateTime();byte[] input;input = new byte[] { 0x5e, 0x3b, 0x5d, 0x00, 0x25, 0x91, 0x00, 0x00 };Assert.AreEqual(new DateTime(2001, 09, 25, 05, 39, 26, 820), (DateTime)type.GetValue(input));input = new byte[] { 0xb6, 0x87, 0xf0, 0x00, 0xd1, 0x8b, 0x00, 0x00 };Assert.AreEqual(new DateTime(1997, 12, 31, 14, 35, 44, 607), (DateTime)type.GetValue(input));input = new byte[] { 0x2d, 0xfd, 0x1c, 0x01, 0x4a, 0x75, 0x00, 0x00 };Assert.AreEqual(new DateTime(1982, 03, 18, 17, 17, 36, 790), (DateTime)type.GetValue(input));input = new byte[] { 0xff, 0x81, 0x8b, 0x01, 0x7f, 0x24, 0x2d, 0x00 };Assert.AreEqual(new DateTime(9999, 12, 31, 23, 59, 59, 997), (DateTime)type.GetValue(input));}        [Test]public void Length(){var type = new SqlDateTime();Assert.Throws
(() => type.GetValue(new byte[9]));Assert.Throws
(() => type.GetValue(new byte[7]));}}}

 

 

SqlSmallDateTime实现

Smalldatetime 是一个不错的数据类型当你需要存储范围值内的日期值(1900~2079)并且他能精确到秒

大多数场景下,精确到秒已经足够了,在一个范围的时间间隔内和精确值不需要太精确的情况下会节省很多空间

smalldatetime 数据类型会只占用4个字节,前2个字节存储自午夜的分钟数,后2个字节存储日期,默认值是1900-1-1

处理的方法跟datetime差不多,只不过使用更小的范围

部分     计算小时    X / 60分钟    X % 60
public class SqlSmallDateTime : ISqlType{    public bool IsVariableLength    {        get { return false; }    }    public short? FixedLength    {        get { return 4; }    }    public object GetValue(byte[] value)    {        if (value.Length != 4)            throw new ArgumentException("Invalid value length: " + value.Length);        ushort time = BitConverter.ToUInt16(value, 0);        ushort date = BitConverter.ToUInt16(value, 2);        return new DateTime(1900, 1, 1, time / 60, time % 60, 0).AddDays(date);    }}

相关测试

using System;using NUnit.Framework;using OrcaMDF.Core.Engine.SqlTypes;namespace OrcaMDF.Core.Tests.Engine.SqlTypes{    [TestFixture]public class SqlSmallDateTimeTests{        [Test]public void GetValue(){var type = new SqlSmallDateTime();var input = new byte[] { 0xab, 0x02, 0x5d, 0x26 };Assert.AreEqual(new DateTime(1926, 11, 22, 11, 23, 0), Convert.ToDateTime(type.GetValue(input)));input = new byte[] { 0x49, 0x03, 0x99, 0x09 };Assert.AreEqual(new DateTime(1906, 9, 24, 14, 1, 0), Convert.ToDateTime(type.GetValue(input)));}        [Test]public void Length(){var type = new SqlSmallDateTime();Assert.Throws
(() => type.GetValue(new byte[3]));Assert.Throws
(() => type.GetValue(new byte[5]));}}}

 

第四篇完

转载地址:http://vddmx.baihongyu.com/

你可能感兴趣的文章
【SPOJ220】Relevant Phrases of Annihilation (SA)
查看>>
P1337 [JSOI2004]平衡点 / 吊打XXX
查看>>
OceanBase架构浅析(二)
查看>>
2018.7.28第一题作业答案 7个题
查看>>
leetcode pow(x,n)实现
查看>>
讨厌的大整数加法
查看>>
移动端监听输入手机号以及判断手机号有效
查看>>
PHP中try、catch、finally的执行顺序
查看>>
课程改进建议
查看>>
我的Android进阶之旅------>Android知识图谱
查看>>
Selenium高级篇Web自动化测试框架
查看>>
Java 面向对象之static,final,匿名对象,内部类,包,修饰符
查看>>
[LeetCode] Consecutive Numbers 连续的数字 --数据库知识(mysql)
查看>>
CoreAnimation 之CATextLayer
查看>>
精通CSS高级Web标准解决方案(2-1 可视化格式模型之框模型)
查看>>
js_总结数据类型在内存中的存储
查看>>
关于电脑BIOS解密,如何解密问题?
查看>>
【入门必备】最佳的 Node.js 学习教程和资料书籍
查看>>
js对象深潜拷贝(从requirejs中抠出来的)
查看>>
mysql创建应用账号
查看>>