/// <summary> /// Generates a unique, sequential, Base36 string, 16 characters long. /// The first 10 characters are the microseconds elapsed since the InService DateTime /// (constant field you hardcode in this file). /// The next 2 characters are a compressed checksum of the MD5 of this host. /// The next 1 character is a reserved constant of 36 ('Z' in Base36). /// The last 3 characters are random number less than 46655 additional for additional uniqueness. /// </summary> /// <param name="delimiter">If provided, formats the ID as four groups of /// 4 characters separated by the delimiter.</param> /// <returns>Returns a unique, sequential, 16-character Base36 string</returns> public static string NewBase36String(string delimiter) { // For 10 chars from timestamp, microseconds since InService, uses Stopwatch... long microseconds = initStaticsReturnMicroseconds(); // For 2 chars from host id MD5... string hostHash = (_hostHash ?? (_hostHash = ComputeHostHash())); // 1 reserved char; static largest base36 digit. // If the same ID system, scheme and sequence is still in use // more than 115.85 years after in-service date, decrements // 'reserved' by 1 for each whole multiple of 115 years // elapsed, up to 35 times max. If the same system, scheme // and sequence is still in service 3,850 years from the // initial go-live, you probably have bigger problems than // ID collisions... int reserved = _reserved; // 3 chars random in Base36 = 46656 units string rndHexStr = getRandomDigits(); StringBuilder sb = new StringBuilder(); sb.Append(Base36Converter.FromInt64(microseconds).PadLeft(10, '0')); sb.Length = 10; sb.Append(hostHash.PadLeft(2, '0')); sb.Length = 12; sb.Append(Base36Converter.FromInt32(reserved)); sb.Length = 13; sb.Append(Base36Converter.FromHex(rndHexStr).PadLeft(3, '0')); sb.Length = 16; if (!string.IsNullOrEmpty(delimiter)) { sb.Insert(12, delimiter); sb.Insert(8, delimiter); sb.Insert(4, delimiter); } return(sb.ToString()); }