好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

解剖SQLSERVER 第四篇 OrcaMDF里对dates类型数据的解析(译) http://improve.dk/parsing-dates-in-orcamdf/ 在SQLSERVER里面有几种不同的date相关类型,当前OrcaMDF 支持三种最常用的date类型:date,datetime,smalldatetime SqlDate实现 date 类型在三种

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

http://improve.dk/parsing-dates-in-orcamdf/

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

SqlDate实现

比较坑爹的是.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)并且他能精确到秒

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

处理的方法跟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  ]));
}
}
}  

第四篇完

查看更多关于解剖SQLSERVER第四篇OrcaMDF里对dates类型数据的解析(译)的详细内容...

  阅读:40次