Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace SomeNameSpace
  7. {
  8.   class CombGuid
  9.   {
  10.  
  11.     /*
  12.      * "COMB" Guids are a little better then standard .Net GUID's
  13.      * for use as primary keys.  The are generated in sequence,
  14.      * which is better for indexing and scanning.  This is similar to
  15.      * the NewSequentialID() functionality in SQL 2005+, but Comb Guid's
  16.      * can be generated outside of the SQL database and passed in as
  17.      * a parameter, so you know in code what your primary key
  18.      * is without having to pull it from the database after insert.
  19.      */
  20.  
  21.  
  22.     #region CombGuid Explaination
  23.     //http://www.ideablade.com/techtip_improve_your_guid.htm
  24.  
  25.     /*********************************
  26.      *
  27.     /// <summary>Create a new Guid.Comb.</summary>
  28.     /// <remarks>
  29.     /// Version by jtmueller, Jul 9, 2002.
  30.     /// <![CDATA[
  31.     /// http://www.informit.com/discussion/index.asp?postid=a8275a70-0698-46f0-8c8f-bf687464628c&rl=1
  32.     /// ]]>
  33.     /// The author wonders:
  34.     /// "One issue is that while the resolution for a DATETIME in SQL Server is 1/300th of a second,
  35.     /// the resolution for a DateTime in .NET is 1/10000th of a second (100 nanoseconds).
  36.     /// This means that the sequential part of the COMB will change more frequently
  37.     /// than in the SQL Server version, but I'm not sure if this is a good or a bad thing."
  38.     /// On the chance that this is a problem, we've gone with the version below.
  39.     /// </remarks>
  40.     public static Guid NewComb() {
  41.       byte[] dateBytes = BitConverter.GetBytes(DateTime.UtcNow.Ticks);
  42.       byte[] guidBytes = Guid.NewGuid().ToByteArray();
  43.       // copy the last six bytes from the date to the last six bytes of the GUID
  44.       Array.Copy(dateBytes, dateBytes.Length - 7, guidBytes, guidBytes.Length - 7, 6);
  45.       return new Guid(guidBytes);
  46.     }
  47.     *
  48.     *********************************/
  49.  
  50.     #endregion
  51.  
  52.     /// <summary>Create a new Guid.Comb.</summary>
  53.     /// <remarks>
  54.     /// Version by glapointe, Aug 16, 2002
  55.     /// <![CDATA[
  56.     /// http://www.informit.com/discussion/index.asp?postid=a8275a70-0698-46f0-8c8f-bf687464628c&rl=1
  57.     /// ]]>
  58.     /// This one purports to "match exactly (or pretty darn close) the combs created in SQL Server."
  59.     /// However, I modified slightly to use UtcNow and static BaseDate values.
  60.     /// UtcNow gives cross-timezone ordering of records inserted with Guid.Comb keys.
  61.     /// </remarks>
  62.     public static Guid NewComb() {
  63.       byte[] guidArray = System.Guid.NewGuid().ToByteArray();
  64.  
  65.       DateTime now = DateTime.UtcNow; // was: DateTime now = DateTime.Now;
  66.  
  67.       // Get the days and milliseconds which will be used to build the byte string
  68.       TimeSpan days = new TimeSpan(now.Ticks - msBaseDateTicks);
  69.       TimeSpan msecs = new TimeSpan(now.Ticks - (new DateTime(now.Year, now.Month, now.Day).Ticks));  
  70.  
  71.       // Convert days and msecs to byte arrays
  72.       // SQL Server is accurate to 1/300th of a millisecond
  73.       // .NET DateTime ticks are in milliseconds
  74.       // so we divide .NET ticks by 3.333333
  75.       byte[] daysArray = BitConverter.GetBytes(days.Days);
  76.       byte[] msecsArray = BitConverter.GetBytes((long)(msecs.TotalMilliseconds / 3.333333));
  77.  
  78.       // Reverse the bytes to match SQL Servers ordering
  79.       Array.Reverse(daysArray);
  80.       Array.Reverse(msecsArray);
  81.  
  82.       // Copy the bytes into the guid
  83.       Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2);
  84.       Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4);
  85.  
  86.       return new System.Guid(guidArray);
  87.     }
  88.  
  89.     /// <summary>Extract datetime part of a Guid.Comb.</summary>
  90.     /// <remarks>
  91.     /// Please note: Because I modified <see cref="NewComb"/> to use Utc datetime,
  92.     /// this function returns the date in Universal Time;
  93.     /// you may want to convert back to local time with
  94.     /// <code>GetDateFromComb(aGuidComb).ToLocalTime();</code>
  95.     /// </remarks>
  96.     public static DateTime GetDateFromComb(System.Guid guid) {
  97.       byte[] daysArray = new byte[4];
  98.       byte[] msecsArray = new byte[4];
  99.       byte[] guidArray = guid.ToByteArray();
  100.  
  101.       // Copy the date parts of the guid to the respective byte arrays.
  102.       Array.Copy(guidArray, guidArray.Length - 6, daysArray, 2, 2);
  103.       Array.Copy(guidArray, guidArray.Length - 4, msecsArray, 0, 4);
  104.  
  105.       // Reverse the arrays to put them into the appropriate order
  106.       Array.Reverse(daysArray);
  107.       Array.Reverse(msecsArray);
  108.  
  109.       // Convert the bytes to ints
  110.       int days = BitConverter.ToInt32(daysArray, 0);
  111.       int msecs = BitConverter.ToInt32(msecsArray, 0);
  112.  
  113.       DateTime date = msBaseDate.AddDays(days);
  114.       date = date.AddMilliseconds(msecs * 3.333333);
  115.  
  116.       return date;
  117.     }
  118.     private static DateTime msBaseDate = new DateTime(1900, 1, 1);
  119.     private static long msBaseDateTicks = msBaseDate.Ticks;
  120.  
  121.   }
  122. }