Package: serial-id
Serial-IdSequential Unique Short & Sortable IdentifierIt is a short sequential identifier that is random but sortable and only uses 80 bits. First 40 bits are for timestamp and rest of the 40 bits are used for randomness.Why's Serial-Id?This is a conversion ofahawker/ulid128 bits implementation to short 80 bits identifier with purpose of sortability and uses Crockford'sBase32encodingInstallationTo install serial-id fromgithub:$pipinstall--upgradegit+https://github.com/mysteryjeans/serial-id.gitTo install serial-id from source:$gitclonehttps://github.com/mysteryjeans/serial-id.git$cdserial-id&&pythonsetup.pyinstallUsageCreate a brand new SerialId.The timestamp value (40-bits) is fromtime.time()with centiseconds precision.The randomness value (40-bits) is fromos.urandom().importserialidserialid.new()<SerialId('4t8ax5bs-6gvqk2sy')>Sequential Ids but with randomnessCreate a new SerialId from an existing 80-bit value with guaranteed sort order.importserialidseq_ids=[]new_sid=serialid.new()for_inrange(0,1000):new_sid=serialid.new_seq(new_sid)seq_ids.append(new_sid)seq_ids[:10]Create a new SerialId from an existing timestamp value, such as adatetimeobject.Supports timestamp values asint,float,str,bytes,bytearray,memoryview,datetime,Timestamp, andSerialIdtypes.importdatetime,serialidserialid.from_timestamp(datetime.datetime(1999,1,1))<SerialId('4t8ax5bs-6gvqk2sy')>Create a new SerialId from an existing randomness value.Supports randomness values asint,float,str,bytes,bytearray,memoryview,Randomnesstypes.importos,serialidrandomness=os.urandom(10)serialid.from_randomness(randomness)<SerialId('4t8ax5bs-sgx82mz4')>For cases when you don't necessarily control the data type (input from external system), you can use theparsemethod
which will attempt to make the correct determination for you. Please note that this will be slightly slower than creating
the instance from the respectivefrom_*method as it needs to make a number of type/conditional checks.Supports values asint,float,str,bytes,bytearray,memoryview, andSerialIdtypes.importserialidvalue=db.model.get_id()## Unsure about datatype -- Could be int or string?serialid.parse(value)# Parses from str, int, float, bytes ...<SerialId('4t8ax5bs-vp61yjkk')>Once you have a SerailId object, there are a number of ways to interact with it.Thetimestampmethod will give you a snapshot view of the first 40-bits of the SerialId while therandomnessmethod
will give you a snapshot of the last 40-bits.importserialidid=serialid.new()id<SerialId('4t8ax5bs-vp61yjkk')>id.timestamp()<Timestamp('4t8ax5bs')>id.randomness()<Randomness('vp61yjkk')>TheSerialId,Timestamp, andRandomnessclasses all derive from the same base class, aMemoryView.AMemoryViewprovides thebin,bytes,hex,int,oct, andstr, methods for changing any values representation.importserialidu=serialid.new()u<SerialId('4t8ax5bs-vp61yjkk')u.timestamp()<Timestamp('4t8ax5bs')>u.timestamp().int165636436000u.timestamp().bytesb'&\x90\xb3j\x13'u.timestamp().datetimedatetime.datetime(2022,6,28,2,12,1,190000)u.randomness().bytesb'\x01c.)\xfa'u.bytes[5:]==u.randomness().bytesTrueu.str'4t8ax5bs-vp61yjkk'u.int182119165340642244955695u.bin'0b100110100100001011001100100001111000001001111100111101001011100000111000101111'u.hex'0x2690b321e09f3d2e0e2f'u.oct'0o46441314417011747513407057'AMemoryViewalso provides rich comparison functionality.importdatetime,time,serialidu1=serialid.new()time.sleep(5)u2=serialid.new()u1<u2Trueu3=serialid.from_timestamp(datetime.datetime(2039,1,1))u1<u2<u3True[u.timestamp().datetimeforuinsorted([u2,u3,u1])][datetime.datetime(2022,6,28,2,24,56,700000),datetime.datetime(2022,6,28,2,25,1,710000),datetime.datetime(2039,1,1,0,0)]ContributingIf you would like to contribute, simply fork the repository, push your changes and send a pull request.
Pull requests will be brought into themasterbranch via a rebase and fast-forward merge with the goal of having a linear branch history with no merge commits.LicenseMIT LicenseWhy not ULID?SerailId provides:80-bit sortable Ids1099511627776 unique Serial Ids per centisecond 100th of a secondLexicographically sortable!Canonically encoded as a 16 character string, as opposed to the 24 character ULIDUses Crockford's base32 for better efficiency and readability (5 bits per character)Case insensitiveNo special characters (URL safe)SpecificationBelow is the current specification of ULID as implemented in this repository.The binary format is implemented.4t8ax5bs           vp61yjkk

|----------|       |----------|
 Timestamp          Randomness
   8chars             8chars
   40bits             40bitsComponentsTimestamp40 bit integerUNIX-time in centisecondsWon't run out of space till the year 2322 (300 years).Randomness40 bitsCryptographically secure source of randomness, if possibleSortingThe left-most character must be sorted first, and the right-most character sorted last (lexical order).
The default ASCII character set must be used. Within the same centiseconds, useserialid.new_seqto guaranteed sort orderEncodingCrockford's Base32 is used as shown. This alphabet excludes the letters I, L, O, and U to avoid confusion and abuse.0123456789abcdefghjkmnpqrstvwxyzString Representationttttttttrrrrrrrr

where
t is Timestamp
r is RandomnessLinksULID Implementation (Python)