using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SomeNameSpace
{
class CombGuid
{
/*
* "COMB" Guids are a little better then standard .Net GUID's
* for use as primary keys. The are generated in sequence,
* which is better for indexing and scanning. This is similar to
* the NewSequentialID() functionality in SQL 2005+, but Comb Guid's
* can be generated outside of the SQL database and passed in as
* a parameter, so you know in code what your primary key
* is without having to pull it from the database after insert.
*/
#region CombGuid Explaination
//http://www.ideablade.com/techtip_improve_your_guid.htm
/*********************************
*
/// <summary>Create a new Guid.Comb.</summary>
/// <remarks>
/// Version by jtmueller, Jul 9, 2002.
/// <![CDATA[
/// http://www.informit.com/discussion/index.asp?postid=a8275a70-0698-46f0-8c8f-bf687464628c&rl=1
/// ]]>
/// The author wonders:
/// "One issue is that while the resolution for a DATETIME in SQL Server is 1/300th of a second,
/// the resolution for a DateTime in .NET is 1/10000th of a second (100 nanoseconds).
/// This means that the sequential part of the COMB will change more frequently
/// than in the SQL Server version, but I'm not sure if this is a good or a bad thing."
/// On the chance that this is a problem, we've gone with the version below.
/// </remarks>
public static Guid NewComb() {
byte[] dateBytes = BitConverter.GetBytes(DateTime.UtcNow.Ticks);
byte[] guidBytes = Guid.NewGuid().ToByteArray();
// copy the last six bytes from the date to the last six bytes of the GUID
Array.Copy(dateBytes, dateBytes.Length - 7, guidBytes, guidBytes.Length - 7, 6);
return new Guid(guidBytes);
}
*
*********************************/
#endregion
/// <summary>Create a new Guid.Comb.</summary>
/// <remarks>
/// Version by glapointe, Aug 16, 2002
/// <![CDATA[
/// http://www.informit.com/discussion/index.asp?postid=a8275a70-0698-46f0-8c8f-bf687464628c&rl=1
/// ]]>
/// This one purports to "match exactly (or pretty darn close) the combs created in SQL Server."
/// However, I modified slightly to use UtcNow and static BaseDate values.
/// UtcNow gives cross-timezone ordering of records inserted with Guid.Comb keys.
/// </remarks>
public static Guid NewComb() {
byte[] guidArray = System.Guid.NewGuid().ToByteArray();
DateTime now = DateTime.UtcNow; // was: DateTime now = DateTime.Now;
// Get the days and milliseconds which will be used to build the byte string
TimeSpan days = new TimeSpan(now.Ticks - msBaseDateTicks);
TimeSpan msecs = new TimeSpan(now.Ticks - (new DateTime(now.Year, now.Month, now.Day).Ticks));
// Convert days and msecs to byte arrays
// SQL Server is accurate to 1/300th of a millisecond
// .NET DateTime ticks are in milliseconds
// so we divide .NET ticks by 3.333333
byte[] daysArray = BitConverter.GetBytes(days.Days);
byte[] msecsArray = BitConverter.GetBytes((long)(msecs.TotalMilliseconds / 3.333333));
// Reverse the bytes to match SQL Servers ordering
Array.Reverse(daysArray);
Array.Reverse(msecsArray);
// Copy the bytes into the guid
Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2);
Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4);
return new System.Guid(guidArray);
}
/// <summary>Extract datetime part of a Guid.Comb.</summary>
/// <remarks>
/// Please note: Because I modified <see cref="NewComb"/> to use Utc datetime,
/// this function returns the date in Universal Time;
/// you may want to convert back to local time with
/// <code>GetDateFromComb(aGuidComb).ToLocalTime();</code>
/// </remarks>
public static DateTime GetDateFromComb(System.Guid guid) {
byte[] daysArray = new byte[4];
byte[] msecsArray = new byte[4];
byte[] guidArray = guid.ToByteArray();
// Copy the date parts of the guid to the respective byte arrays.
Array.Copy(guidArray, guidArray.Length - 6, daysArray, 2, 2);
Array.Copy(guidArray, guidArray.Length - 4, msecsArray, 0, 4);
// Reverse the arrays to put them into the appropriate order
Array.Reverse(daysArray);
Array.Reverse(msecsArray);
// Convert the bytes to ints
int days = BitConverter.ToInt32(daysArray, 0);
int msecs = BitConverter.ToInt32(msecsArray, 0);
DateTime date = msBaseDate.AddDays(days);
date = date.AddMilliseconds(msecs * 3.333333);
return date;
}
private static DateTime msBaseDate = new DateTime(1900, 1, 1);
private static long msBaseDateTicks = msBaseDate.Ticks;
}
}