Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Good algorithm to convert timestamp to a shorter alphanumeric representation

Tags:

algorithm

What would be a good algorithm for taking a timestamp that contains year, month, day, hour, minute, second and convert it into a 7 digit or less(but consistent) alphanumeric representation. The alphanumeric representation won't distinguish between upper and lower case letters.

like image 862
Mike Avatar asked Mar 23 '11 13:03

Mike


2 Answers

Let's do some maths

You can use 7 alphanumeric digits. Each alphanumeric digit take a value from 36 possible different values (26 letters, 10 decimal digits) So we have 36^7 different values, that is 78364164096.

Now we compute the number of different values needed to represent a given timestamp in one year. To simplify things a bit we will allow some values that will never happen (ex: 31th november).

Thus, we have

month: 12  -> coded from 0 to 11
day: 31  -> coded from 0 to 30
hour: 24
minute: 60
second: 60 

which gives use 32140800 different possibilites

We now divide 78364164096 / 32140800 which is ~2438, thus we will give an enumeration of timestamps from 00:00 jan 1 0000 to 23:59 dec 31 2437

The encoding is then

X = second + minute*60 + hour*60*60 + 
    day*60*60*24 + month*60*60*24*31 + 
    year*60*60*24*31*12

And the decoding is

second = X mod 60
minute = (X div 60) mod 60
hour = (X div 60*60) mod 24
day = (X div 60*60*24) mod 31
month = (X div 60*60*24*31) mod 12
year = X div 60*60*24*31*12

Let's look at an example:

Suppose you want to encode the date december 20, 1998, 05:33:12 So you would have

second: 12
minute: 33
hour: 5
day: 19   -> note that we encode days in the range 0..31
month: 11  -> note that we conde months in the range 0..11
year: 1998

So we compute:

X = 12 + 33*60 + 5*60*60 + 
        19*60*60*24 + 11*60*60*24*31 + 
        1998*60*60*24*31*12

That is, X = 12 + 1980 + 18000 + 1641600 + 29462400 + 64217318400 = 64248442392

And now we decode it

second = 64248442392 mod 60  = 12
minute = (64248442392 div 60) mod 60 = 33
hour = (64248442392 div 60*60) mod 24 = 5
day = (64248442392 div 60*60*24) mod 31 = 19
month = (64248442392 div 60*60*24*31) mod 12 = 11
year = 64248442392 div 60*60*24*31*12 = 1998
like image 167
gusbro Avatar answered Oct 16 '22 08:10

gusbro


Consider a higher than decimal numeral system. For example, the hexadecimal numeral system is base-16. Let's say in our new numeral system, we have digits 0-9, the lower-case alphabet (a-z) and the upper case alphabet (A-Z). This gives us 62 possible digits, so we can use a base-62 numeral system. Here's some Javascript code to do the conversion -

function createConverter() {
    var charRange = (start, end) => Array.from(Array(end-start), 
                                         (v, i) => String.fromCharCode(i + start))

    var digits = charRange(48, 48+10)             // 0 to 9
                   .concat(charRange(97, 97+26))  // a to b
                   .concat(charRange(65, 65+26))  // A to B

    var base = digits.length

    return function(decimal) {
            var result = ""
            while (decimal >= base) {
                result = digits[decimal % base] + result
                decimal = parseInt(decimal / base)
            }
            result = digits[decimal] + result
            return result
        }
}

var convert = createConverter()
convert(parseInt(Date.now() / 1000)) // returns a 6-digit alphanumeric string 

charRange is just a utility arrow function to create a range of characters from ASCII codes

digits represents all the valid digits in our numeral system. You can add more valid digits (like special chars) to this list

base is the number (in decimal) of available digits

Output encoded in this base-62 numeral system will stay 6 digits long for more than 1,700 years.

EDIT: Realized Date.now() returns timestamp in milliseconds not seconds, so I've updated my answer to reflect that

like image 33
0cd Avatar answered Oct 16 '22 07:10

0cd