-1

I need to encode current datetime into some unique string to store it in database. I found this article how to generate a unique token which expires after 24 hours? but for me generated token is to long (34 symbols)

Is there some other similar way to encode shorter string?


Perfect size <= 10 symbols.

Community
  • 1
  • 1
user3770925
  • 223
  • 2
  • 5
  • 12
  • what you have tried so far – BRAHIM Kamel Jul 24 '14 at 14:48
  • 1
    What granularity do you need? (Just *date* is easy - yyyyMMdd. I assume you need more than that.) Oh, and what range of values? (For example, only values in the 21st century? Only values between 2014 and 2024? All these things matter...) – Jon Skeet Jul 24 '14 at 14:52
  • @K.B, i store this tokens into Azure Table storage. Here is idea to generate random 5 symbols token (`var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; var random = new Random(); var result = new string( Enumerable.Repeat(chars, 8) .Select(s => s[random.Next(s.Length)]) .ToArray());`) and then, when user pass some token go to table storage and get some data by that token. But this increase number of requests, so i try to avoid it – user3770925 Jul 24 '14 at 15:02
  • @JonSkeet, `DateTime.UtcNow` this is what i want to encode. – user3770925 Jul 24 '14 at 15:03
  • @user3770925: That doesn't answer either of my questions. – Jon Skeet Jul 24 '14 at 15:09
  • @JonSkeet, i don't know how long this site will work, so i can't answer what range values. Just something like this.. [DateTime.Now; +infinity] – user3770925 Jul 24 '14 at 15:17
  • @user3770925: Well then that's clearly going to take up to an infinite amount of space to encode. I suggest you think of a more reasonable upper bound. And you *still* haven't answered the granularity question. Do you only care down to the hour? Minute? Second? – Jon Skeet Jul 24 '14 at 15:19
  • @JonSkeet, to seconds – user3770925 Jul 24 '14 at 15:20
  • Now to infinity will definitely not stand in a 10 chars string. – Guillaume Jul 24 '14 at 15:20

3 Answers3

1

I'd ask why? What are you trying to do? If you want to timestamp something like a log entry then just use the datetime value - every database type I know has a built in date/time type.

If you're trying to generate a unique Id for use as something like a primary key then this would be a bad idea - I've yet to find a good case for using a date based unique id.

It would be much better to have an auto-incrementing integer or even GUID value. If you wanted you could then add a timestamp column to the database

Swomble
  • 874
  • 8
  • 17
  • 1
    It's only for accessing to hidden page on site, there is no need is very strong security but.. So case with int parameter will be too unsecure.. – user3770925 Jul 24 '14 at 15:08
  • Can you absolutely guarantee that you won't get two requests at the same time? Although using the DateTime.Ticks parameter will probably give you the resolution you need, it will mean that anyone can potentially hit that page – Swomble Jul 24 '14 at 15:20
1

You can use a tick (DateTime.Ticks for instance) but don't store the tick as simple string, encode the bits. If you use a long tick (64bit) you should consider ASCII85 encoding of the bytes so it wont exceed 10 symbols.

var tickBytes = BitConverter.GetBytes(DateTime.UtcNow.Ticks);
string encodedTicks = new Ascii85().Encode(tickBytes);

If you chose a 32bit tick, base 64 should be fine.


For a readable tick with precision to second (less precise than the previous solution)

long origin = new DateTime(2014, 7, 24).Ticks / TimeSpan.TicksPerSecond;
long customTicks = (DateTime.UtcNow.Ticks / TimeSpan.TicksPerSecond) - origin;
string readableTicks = customTicks.ToString(CultureInfo.InvariantCulture);

That will stay on 10 chars or less for ~300 years.

Guillaume
  • 12,824
  • 3
  • 40
  • 48
0

Okay, if you want it from "about now" to some point in the future, and you want seconds granularity, and you want ASCII symbols, let's assume base64.

With 8 characters of base64, we can encode 6 bytes of data. That will give us 248 different values, which allows about 9 million years-worth of seconds. Given that range, we might as well use the DateTime.Ticks property and divide by ticks-per-second, not worrying about the epoch. Full code coming later if you want it, but as a list of steps:

  • Take DateTime.UtcNow.Ticks
  • Divide by TimeSpan.TicksPerSecond
  • Convert the result into a byte[], e.g. with BitConverter.GetBytes(long)
  • Encode the least-significant 6 bits (I'm hopeless with endianness - either the first or last 6 bytes of the byte[] as base64 using Convert.ToBase64String
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194