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))