Aaron Anodide
Aaron Anodide

Reputation: 17196

Way to generate a unique number that does not repeat in a reasonable time?

I'm integrating/testing with a remote web service and even though it's the "QA" endpoint, it still enforces a unique email address on every call.

I can think of DateTime.Now.Ticks (e.g. 634970372342724417) and Guid.NewGuid(), but neither of those can be coalesced into an email with max. 20 chars (or can they?).

I suppose it's not that hard to write out to a file a number that contains the last number used and then use [email protected], [email protected], etc... but if I can avoid persisting state I always do.

Does anyone have a trick or an algorithm that gives something of a short length "guid" that is unique to a reasonably long time period (say a year) that I could use for my email addresses of max length 20 chars with (max length of guid) = 14 = 20 - length of "@x.com"?

Upvotes: 18

Views: 66242

Answers (6)

Ali Shakkouf
Ali Shakkouf

Reputation: 11

    public async Task<string> GeneratePatientNumberAsync()
    {
        var random = new Random();
        var chars = DateTime.Now.Ticks + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789" + DateTime.Now.Ticks;
        return new string(Enumerable.Repeat(chars, 5)
            .Select(s => s[random.Next(s.Length)]).ToArray());
    }

Upvotes: 1

Martijn Willegers
Martijn Willegers

Reputation: 11

    /// <summary>
    /// Get a unique reference number.
    /// </summary>
    /// <returns></returns>
    public string GetUniqueReferenceNumber(char firstChar)
    {
        var ticks = DateTime.Now.Ticks;
        var ticksString = ticks.ToString();
        var ticksSubString = ticksString.Substring((ticksString.Length - 15 > 0) ? ticksString.Length - 15 : 0); 
        if (this.currentTicks.Equals(ticks))
        {
            this.currentReference++;

            if (this.currentReference >= 9999)
            {
                // Only when there are very fast computers.
                System.Threading.Thread.Sleep(1);
            }

            return (firstChar + ticksSubString + this.currentReference.ToString("D4")).PadRight(20, '9');
        }

        this.currentReference = -1;
        this.currentTicks = ticks;
        return (firstChar + ticksSubString).PadRight(20, '9');
    }

In my case I needed to create a unique reference number with a unique first character and a maximum of 20 characters. Maybe you can use the function below, it allows you to create 9999 unique numbers within one tick. (zero included)

Of course you can create your own implementation without the first character and maximum character count of 20

Upvotes: 0

Michel Ayres
Michel Ayres

Reputation: 5985

Just to add... If you want to use number only from ticks, you can by using substring, for example:

int onlyThisAmount = 20;
string ticks = DateTime.Now.Ticks.ToString();
ticks = ticks.Substring(ticks.Length - onlyThisAmount);

Upvotes: 0

EtherDragon
EtherDragon

Reputation: 2698

If you get the following digits from your date-time, you should be able to make it work... Soemthing like:

DateTime.Now.ToString("yyMMddHHmmssff");

which is 16 characters, leaving 4 for some other prefix as you need.

So, Feb 21, 2013, at approximately 10:21 would be "130321102142" and the next one would be "130321102169", etc...

Have a look at http://msdn.microsoft.com/en-us/library/zdtaw1bw.aspx for more details on datetime formatting.

Upvotes: 17

Patrick
Patrick

Reputation: 23629

If you assume that you will not generate two e-mail addresses at the same 'tick', then you can indeed use the ticks to generate an e-mail address.

However, if ticks is a 64-bit number, and you write out that number, you will end up with more than 20 characters.

The trick is to encode your 64-bit number using a different scheme. Assume that you can use the 26 characters from the western alphabet + 10 digits. This makes 36 possible characters. If you take 5 bits, you can represent 32 characters. That should be enough. Take the 64-bits and divide them in groups of 5 bits (64 /5 is about 13 groups). Translate every 5 bits to one character. That way you end up with 13 characters, and you can still add a character in front of it).

long ticks = DateTime.Now.Ticks;
byte[] bytes = BitConverter.GetBytes(ticks);
string id = Convert.ToBase64String(bytes)
                        .Replace('+', '_')
                        .Replace('/', '-')
                        .TrimEnd('=');
Console.WriteLine (id);

Yields:

Gq1rNzbezwg

Upvotes: 26

Abdusalam Ben Haj
Abdusalam Ben Haj

Reputation: 5433

Since you specified at least 1 second between each call, this should work :

DateTime.Now.ToString("yyyyMMddHHmmss");

its exactly 14 characters.

Upvotes: 13

Related Questions