Epoch Timestamp Hashing
⚠️ WARNING: This page is obsolete
Articles typically receive this designation when the technology they describe is no longer relevant, code provided is later deemed to be of poor quality, or the topics discussed are better presented in future articles. Articles like this are retained for the sake of preservation, but their content should be critically assessed.
I was recently presented with the need to rename a folder of images based on a timestamp. This way, I can keep saving new files in that folder with overlapping filenames (i.e., 01.jpg, 02.jpg, 03.jpg, etc.), and every time I run this script all images are prepended with a timestamp. I still want the files to be sorted alphabetically, which is why an alphabetical timestamp (rather than a random hash) is preferred.
- At first I considered a long date such as 2014-04-19-01.jpg, but that adds so much text!…also, it doesn’t include time of day.
- If I include time of day, it becomes 2014-04-19-09-16-23-01.jpg
- If I eliminate dashes to shorten it, it becomes hard to read, but might work 140419091623-01.jpg
- If I use Unix Epoch time, it becomes 1397912944-01.jpg
The result I came up with uses base conversion and a string table of numbers and letters (in alphabetical order) to create a second-respecting timestamp hash using an arbitrary number of characters. For simplicity, I used 36 characters: 0-9, and a-z. I then wrote two functions to perform arbitrary base conversion, pulling characters from the hash. Although I could have nearly doubled my available characters by including the full ASCII table, respecting capitalization, I decided to keep it simple. The scheme goes like this:
- Determine the date / time: 19-Apr-2014 13:08:55
- Create an integer of Unix Epoch time (seconds past Jan 1, 1970): 1397912935
- Do a base conversion from a character list: n4a4iv
- My file name now becomes n4a4iv-01.jpg - I can accept this!and when I sort the folder alphabetically, they’re in order by the timestamp
I can now represent any modern time, down to the second, with 6 characters. Here’s some example output:
19-Apr-2014 13:08:55 <-> 1397912935 <-> n4a4iv
19-Apr-2014 13:08:56 <-> 1397912936 <-> n4a4iw
19-Apr-2014 13:08:57 <-> 1397912937 <-> n4a4ix
19-Apr-2014 13:08:58 <-> 1397912938 <-> n4a4iy
19-Apr-2014 13:08:59 <-> 1397912939 <-> n4a4iz
19-Apr-2014 13:09:00 <-> 1397912940 <-> n4a4j0
19-Apr-2014 13:09:01 <-> 1397912941 <-> n4a4j1
19-Apr-2014 13:09:02 <-> 1397912942 <-> n4a4j2
19-Apr-2014 13:09:03 <-> 1397912943 <-> n4a4j3
19-Apr-2014 13:09:04 <-> 1397912944 <-> n4a4j4
Interestingly, if I change my hash characters away from the list of 36 alphanumerics and replace it with just 0 and 1, I can encode/decode the date in binary:
19-Apr-2014 13:27:28 <-> 1397914048 <-> 1010011010100100111100111000000
19-Apr-2014 13:27:29 <-> 1397914049 <-> 1010011010100100111100111000001
19-Apr-2014 13:27:30 <-> 1397914050 <-> 1010011010100100111100111000010
19-Apr-2014 13:27:31 <-> 1397914051 <-> 1010011010100100111100111000011
19-Apr-2014 13:27:32 <-> 1397914052 <-> 1010011010100100111100111000100
19-Apr-2014 13:27:33 <-> 1397914053 <-> 1010011010100100111100111000101
19-Apr-2014 13:27:34 <-> 1397914054 <-> 1010011010100100111100111000110
19-Apr-2014 13:27:35 <-> 1397914055 <-> 1010011010100100111100111000111
19-Apr-2014 13:27:36 <-> 1397914056 <-> 1010011010100100111100111001000
19-Apr-2014 13:27:37 <-> 1397914057 <-> 1010011010100100111100111001001
Here’s the code to generate / decode Unix epoch timestamps in Python:
hashchars='0123456789abcdefghijklmnopqrstuvwxyz'
#hashchars='01' #for binary
def epochToHash(n):
hash=''
while n>0:
hash = hashchars[int(n % len(hashchars))] + hash
n = int(n / len(hashchars))
return hash
def epochFromHash(s):
s=s[::-1]
epoch=0
for pos in range(len(s)):
epoch+=hashchars.find(s[pos])*(len(hashchars)**pos)
return epoch
import time
t=int(time.time())
for i in range(10):
t=t+1
print(time.strftime("%d-%b-%Y %H:%M:%S", time.gmtime(t)),
"<->", t,"<->",epochToHash(t))