Last active
October 24, 2020 22:15
-
-
Save fabiolimace/c3da33d84683fadfa0cba63e433868a2 to your computer and use it in GitHub Desktop.
Generate COMB UUID/GUID with nanosecond resolution in Java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package your.package.name; | |
import java.security.SecureRandom; | |
import java.time.Instant; | |
import java.util.UUID; | |
/** | |
* A UUID generator that creates a COMB GUID with nanoseconds resolution. | |
* | |
* It borrows the main idea from ULID and COMB generators: a concatenation of | |
* time and random bytes. It is composed of 64 bits for time and 64 for random | |
* bits. | |
* | |
* A Nano COMB has two components: | |
* | |
* 1. Time camponent (64 bits): nanoseconds since 1970 | |
* | |
* 2. Random component (64 bits): a value generated by a secure random | |
* generator. | |
* | |
* Maximum time component year is ~2262 A.D. (2^63/10^9/60/60/24/365.25 + 1970) | |
* | |
* Tags: uuid guid comb comb-guid comb-uuid uuid-generator guid-generator comb-generator generator comb time random | |
* | |
* @author: Fabio Lima 2020 | |
*/ | |
public final class NanoCombCreator { | |
private long prevTime = System.currentTimeMillis(); | |
private long prevNano = System.nanoTime(); | |
private static final long ONE_MILLION_NANOSECONDS = 1_000_000L; | |
private static final SecureRandom SECURE_RANDOM = new SecureRandom(); | |
/** | |
* Returns a time component in nanoseconds. | |
* | |
* It uses `System.currentTimeMillis()` to get the system time in milliseconds | |
* accuracy. The nanoseconds resolution is simulated by calling | |
* `System.nanoTime()` between subsequent calls within the same millisecond. | |
* It's not precise, but it provides some monotonicity to the values generates. | |
* | |
* @return the current time in nanoseconds | |
*/ | |
private synchronized long getTimeComponent() { | |
long time = System.currentTimeMillis(); | |
long nano = System.nanoTime(); | |
long elapsed = 0; // nanoseconds since last call | |
if (time == prevTime) { | |
elapsed = (nano - prevNano); | |
} else { | |
prevNano = nano; | |
} | |
prevTime = time; | |
return (time * ONE_MILLION_NANOSECONDS) + elapsed; | |
} | |
/** | |
* Returns the random component using a secure random generator. | |
* | |
* @return a random value. | |
*/ | |
private synchronized long getRandomComponent() { | |
return SECURE_RANDOM.nextLong(); | |
} | |
/** | |
* Returns a Nano COMB. | |
* | |
* A Nano COMB is inspired on ULID and COMB generators. | |
* | |
* It is composed of 64 bits for time and 64 for random bits. | |
* | |
* @return a UUID | |
*/ | |
public synchronized UUID create() { | |
final long timeBits = getTimeComponent(); | |
final long randomBits = getRandomComponent(); | |
return new UUID(timeBits, randomBits); | |
} | |
/** | |
* Test method that generates many Nano COMBs in a loop. | |
* | |
* @param args | |
*/ | |
public static void main(String[] args) { | |
NanoCombCreator creator = new NanoCombCreator(); | |
for (int i = 0; i < 100; i++) { | |
// Generate a Nano COMB | |
UUID uuid = creator.create(); | |
// Extract the milliseconds and nanoseconds | |
long milliseconds = uuid.getMostSignificantBits() / ONE_MILLION_NANOSECONDS; | |
long nanoseconds = uuid.getMostSignificantBits() & ONE_MILLION_NANOSECONDS; | |
// Instantiate an instant using the milliseconds and nanoseconds | |
Instant time = Instant.ofEpochMilli(milliseconds).plusNanos(nanoseconds); | |
// Print the UUID and the time it was generated (UTC) | |
System.out.println("UUID: '" + uuid + "', time: " + time); | |
} | |
} | |
} | |
// OUTPUT: | |
// | |
// UUID: '16410b91-6e48-5769-15a0-c2e40593f728', time: 2020-10-24T21:41:01.569541248Z | |
// UUID: '16410b91-7283-a200-a74d-c903b23126bc', time: 2020-10-24T21:41:01.640197120Z | |
// UUID: '16410b91-7284-d51a-154f-a0528d5924d3', time: 2020-10-24T21:41:01.640278528Z | |
// UUID: '16410b91-7286-924b-ecf7-3b3e0cf69d3f', time: 2020-10-24T21:41:01.640393792Z | |
// UUID: '16410b91-7287-9322-b780-5dc116f837b7', time: 2020-10-24T21:41:01.640459264Z | |
// UUID: '16410b91-7288-e4a9-eac3-72a8a7ca0afe', time: 2020-10-24T21:41:01.640540672Z | |
// UUID: '16410b91-728a-45c7-ddf5-5d213eb6a132', time: 2020-10-24T21:41:01.640671808Z | |
// UUID: '16410b91-728b-5a2d-7b3c-14656a0a10fc', time: 2020-10-24T21:41:01.640737792Z | |
// UUID: '16410b91-728c-abd5-6e15-b38781250ef5', time: 2020-10-24T21:41:01.640787008Z | |
// UUID: '16410b91-7292-e440-c088-f93a8185c78d', time: 2020-10-24T21:41:01.641147520Z | |
// UUID: '16410b91-7293-e216-b672-f7d58f9fe278', time: 2020-10-24T21:41:01.641213504Z | |
// UUID: '16410b91-7295-5c2d-5160-f57780c58655', time: 2020-10-24T21:41:01.641344064Z | |
// UUID: '16410b91-7296-cb55-6ad5-17c2cc852862', time: 2020-10-24T21:41:01.641410176Z | |
// UUID: '16410b91-7298-9407-8f1b-cc6d68a9e083', time: 2020-10-24T21:41:01.641524288Z | |
// UUID: '16410b91-729a-1345-b386-4d63561c489e', time: 2020-10-24T21:41:01.641655936Z | |
// UUID: '16410b91-729b-7ef4-767b-7abe334a9c9a', time: 2020-10-24T21:41:01.641737856Z | |
// UUID: '16410b91-729d-44d7-24de-6b350ccbefda', time: 2020-10-24T21:41:01.641868416Z | |
// UUID: '16410b91-729e-903b-4829-833131df868e', time: 2020-10-24T21:41:01.641917504Z | |
// UUID: '16410b91-72a0-3594-cec7-497dcb6511c7', time: 2020-10-24T21:41:01.641Z | |
// UUID: '16410b91-72a1-364d-bc1c-fbfa9dbeefa9', time: 2020-10-24T21:41:01.641066112Z | |
// UUID: '16410b91-72a2-2680-3761-035b38c80564', time: 2020-10-24T21:41:01.642131584Z | |
// UUID: '16410b91-72a3-c5da-f72b-013316ae31d8', time: 2020-10-24T21:41:01.642213056Z | |
// UUID: '16410b91-72a4-cfa4-a3a7-7927d7f63ad1', time: 2020-10-24T21:41:01.642279040Z | |
// UUID: '16410b91-72a6-5e34-4e1a-c74b85fbb39f', time: 2020-10-24T21:41:01.642410112Z | |
// UUID: '16410b91-72a7-678c-7098-fc9bb3063588', time: 2020-10-24T21:41:01.642475648Z | |
// UUID: '16410b91-72a8-75cf-9803-da85d9f7391e', time: 2020-10-24T21:41:01.642540736Z | |
// UUID: '16410b91-72aa-bf7c-21ac-57e3c817fca4', time: 2020-10-24T21:41:01.642655936Z | |
// UUID: '16410b91-72ac-3450-9d1b-8959c9957039', time: 2020-10-24T21:41:01.642786496Z | |
// UUID: '16410b91-72ad-c6c8-8e18-2c39984bc5b0', time: 2020-10-24T21:41:01.642868928Z | |
// UUID: '16410b91-72ae-ca91-aa4a-682084b02be5', time: 2020-10-24T21:41:01.642934400Z | |
// UUID: '16410b91-72af-cc63-1721-895fbf0e157a', time: 2020-10-24T21:41:01.642999488Z | |
// UUID: '16410b91-72b1-68c0-46c6-9af7ebca0d71', time: 2020-10-24T21:41:01.643081984Z | |
// UUID: '16410b91-72b2-8707-b4fa-5a29b2005f9a', time: 2020-10-24T21:41:01.643131584Z | |
// UUID: '16410b91-72b3-ff6d-7ab9-9b8653db726f', time: 2020-10-24T21:41:01.643213568Z | |
// UUID: '16410b91-72b4-fb77-56af-3243ab595d49', time: 2020-10-24T21:41:01.643279104Z | |
// UUID: '16410b91-72b5-eb26-5ff5-abc45cb98ae6', time: 2020-10-24T21:41:01.643344576Z | |
// UUID: '16410b91-72b7-cc2a-526e-2220f8d16b82', time: 2020-10-24T21:41:01.643475136Z | |
// UUID: '16410b91-72b8-c892-9527-a9612a664722', time: 2020-10-24T21:41:01.643540672Z | |
// UUID: '16410b91-72ba-182d-6ec9-962ea678153f', time: 2020-10-24T21:41:01.643655360Z | |
// UUID: '16410b91-72bb-a9cc-e83b-f0f77ea9bcf7', time: 2020-10-24T21:41:01.643720960Z | |
// UUID: '16410b91-72bc-ad57-ce53-8f1886523766', time: 2020-10-24T21:41:01.643786496Z | |
// UUID: '16410b91-72bd-f0d5-d0f4-21c5803b05fc', time: 2020-10-24T21:41:01.643868416Z | |
// UUID: '16410b91-72bf-2664-808b-69831505c7b8', time: 2020-10-24T21:41:01.643983616Z | |
// UUID: '16410b91-72c0-ab00-fd09-e7eba03dfe47', time: 2020-10-24T21:41:01.644000512Z | |
// UUID: '16410b91-72c1-a889-3de9-8208a0d8e31c', time: 2020-10-24T21:41:01.644065536Z | |
// UUID: '16410b91-72c2-a220-8d10-f0482a2bcaae', time: 2020-10-24T21:41:01.644131584Z | |
// UUID: '16410b91-72c4-0e6f-4ea4-5fe7cb4546ec', time: 2020-10-24T21:41:01.644262720Z | |
// UUID: '16410b91-72c5-0681-0fd2-d25ed4728763', time: 2020-10-24T21:41:01.644328192Z | |
// UUID: '16410b91-72c6-4d7b-9666-3ef582389fcc', time: 2020-10-24T21:41:01.644409664Z | |
// UUID: '16410b91-72c7-4a52-071b-7ef8592e903f', time: 2020-10-24T21:41:01.644475712Z | |
// UUID: '16410b91-72c8-471f-fd0a-6036f6299f75', time: 2020-10-24T21:41:01.644541184Z | |
// UUID: '16410b91-72c9-8a30-6ddf-238d6569aeb2', time: 2020-10-24T21:41:01.644590336Z | |
// UUID: '16410b91-72ca-a42c-ee4c-c066f301ded1', time: 2020-10-24T21:41:01.644655360Z | |
// UUID: '16410b91-72cb-eb29-7e63-039c3e676484', time: 2020-10-24T21:41:01.644737792Z | |
// UUID: '16410b91-72cc-e996-8c0c-bc1804afaa50', time: 2020-10-24T21:41:01.644802816Z | |
// UUID: '16410b91-72ce-1b2a-b9ca-5a0eb9eb6c97', time: 2020-10-24T21:41:01.644918016Z | |
// UUID: '16410b91-72cf-ed40-981e-58572f1a0343', time: 2020-10-24T21:41:01.645999488Z | |
// UUID: '16410b91-72d0-cf70-c346-30b4e8ec5742', time: 2020-10-24T21:41:01.645016960Z | |
// UUID: '16410b91-72d2-167b-7151-51426305d8bf', time: 2020-10-24T21:41:01.645131648Z | |
// UUID: '16410b91-72d3-02e6-7194-355272f16654', time: 2020-10-24T21:41:01.645197184Z | |
// UUID: '16410b91-72d4-21ee-6850-ec5a96e4fa79', time: 2020-10-24T21:41:01.645262208Z | |
// UUID: '16410b91-72d5-8f1b-f5fb-3a4468ce898d', time: 2020-10-24T21:41:01.645328192Z | |
// UUID: '16410b91-72d6-7f9b-8848-d1ae9070d6f1', time: 2020-10-24T21:41:01.645410112Z | |
// UUID: '16410b91-72d7-ff34-e5a3-5cdc80559d22', time: 2020-10-24T21:41:01.645475648Z | |
// UUID: '16410b91-72d9-dec2-0ac5-22db48c5586b', time: 2020-10-24T21:41:01.645606784Z | |
// UUID: '16410b91-72db-0428-aa36-ffdeb845569c', time: 2020-10-24T21:41:01.645720896Z | |
// UUID: '16410b91-72dc-302e-2a84-e6833c0422be', time: 2020-10-24T21:41:01.645786432Z | |
// UUID: '16410b91-72dd-1405-609a-c30fdfdcdad5', time: 2020-10-24T21:41:01.645851968Z | |
// UUID: '16410b91-72de-534f-ce22-2d0d81f2d2f8', time: 2020-10-24T21:41:01.645934464Z | |
// UUID: '16410b91-72df-2f80-c0f5-be207978e4fc', time: 2020-10-24T21:41:01.646983552Z | |
// UUID: '16410b91-72e0-1314-56ae-2c3c4761b296', time: 2020-10-24T21:41:01.646000512Z | |
// UUID: '16410b91-72e1-4568-6335-1ae2ad16b83a', time: 2020-10-24T21:41:01.646081984Z | |
// UUID: '16410b91-72e2-1cff-a7fa-e402ce2d723c', time: 2020-10-24T21:41:01.646131136Z | |
// UUID: '16410b91-72e3-538f-a65c-b29e2539be7e', time: 2020-10-24T21:41:01.646213504Z | |
// UUID: '16410b91-72e4-3d5b-0b06-78775e0984b8', time: 2020-10-24T21:41:01.646262208Z | |
// UUID: '16410b91-72e5-1eda-947f-18a35d504df5', time: 2020-10-24T21:41:01.646328256Z | |
// UUID: '16410b91-72e6-6172-5628-ad98dc142383', time: 2020-10-24T21:41:01.646409664Z | |
// UUID: '16410b91-72e7-51b8-75f6-bb38a4332c0f', time: 2020-10-24T21:41:01.646475136Z | |
// UUID: '16410b91-72e8-f298-295d-eb77ac92079a', time: 2020-10-24T21:41:01.646541184Z | |
// UUID: '16410b91-72e9-d6a4-409a-2647d33245b6', time: 2020-10-24T21:41:01.646606720Z | |
// UUID: '16410b91-72ea-b9b5-31dd-67c934019032', time: 2020-10-24T21:41:01.646655360Z | |
// UUID: '16410b91-72eb-edb2-1ba3-b6428e17469a', time: 2020-10-24T21:41:01.646737280Z | |
// UUID: '16410b91-72ec-c664-233e-99cb4e987089', time: 2020-10-24T21:41:01.646803392Z | |
// UUID: '16410b91-72ee-18f2-6879-4bf1e2306b9f', time: 2020-10-24T21:41:01.646917568Z | |
// UUID: '16410b91-72ee-71c0-b87f-8d5a5f374637', time: 2020-10-24T21:41:01.647933952Z | |
// UUID: '16410b91-72ef-4a7e-c8de-02e417b506a0', time: 2020-10-24T21:41:01.648Z | |
// UUID: '16410b91-72f0-a1c3-4fb3-a6d4e7f4d102', time: 2020-10-24T21:41:01.647000064Z | |
// UUID: '16410b91-72f1-8ed1-9b05-8cf136b44922', time: 2020-10-24T21:41:01.647066112Z | |
// UUID: '16410b91-72f3-222e-3024-26b8cab9374f', time: 2020-10-24T21:41:01.647197120Z | |
// UUID: '16410b91-72f4-0486-db01-7062b6de2ae5', time: 2020-10-24T21:41:01.647262144Z | |
// UUID: '16410b91-72f4-de2a-4c35-56432aba719f', time: 2020-10-24T21:41:01.647279040Z | |
// UUID: '16410b91-72f5-fdd3-dc76-f220bfa2b728', time: 2020-10-24T21:41:01.647344128Z | |
// UUID: '16410b91-72f6-d29f-201a-95e778539989', time: 2020-10-24T21:41:01.647410112Z | |
// UUID: '16410b91-72f7-fc0a-0da9-07a9f70a1e35', time: 2020-10-24T21:41:01.647475136Z | |
// UUID: '16410b91-72f8-c39e-6b2b-2574d9780e2d', time: 2020-10-24T21:41:01.647541184Z | |
// UUID: '16410b91-72f9-ba3e-5e0d-9513334160f8', time: 2020-10-24T21:41:01.647590336Z | |
// UUID: '16410b91-72fb-429a-3a45-f532c7ee8485', time: 2020-10-24T21:41:01.647737792Z | |
// UUID: '16410b91-72fc-2eb5-f91b-eab43c2aa2e4', time: 2020-10-24T21:41:01.647786944Z | |
// UUID: '16410b91-72fd-b400-26dc-dbc4d235e214', time: 2020-10-24T21:41:01.648851968Z | |
// UUID: '16410b91-72fe-8680-a161-823e569b1691', time: 2020-10-24T21:41:01.648918016Z | |
// |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment