cowtowncoder / java-uuid-generator

Java Uuid Generator (JUG) is a Java library for generating all standard UUID versions (v1 - v7)
Apache License 2.0
730 stars 104 forks source link

Add `UUIDUtil.extractTimestamp()` for extracting 64-bit timestamp for all timestamp-based versions #81

Closed gabrielbalan closed 7 months ago

gabrielbalan commented 1 year ago

java.util.UUID#timestamp() only works for version 1 UUIDs.

It would be nice to have similar functionality for version 6 UUIDs. E.g. a static method in TimeBasedReorderedGenerator, something along the lines of

public static long timestamp(UUID uuid)
{
    assert(uuid.version()==6);
    return ((uuid.getMostSignificantBits()>>>4) & ~0xFFF) | (uuid.getMostSignificantBits()&0xFFF);
}

Better yet, a static method in UUIDUtil that returns the number of millis since unix epoch for versions 1, 6 and 7 UUIDs.

thank you very much Gabriel

cowtowncoder commented 1 year ago

I don't think this belongs in generator, however, there is class UUIDUtil where helper method(s) could be added.

Calculation for version 1 is bit more complicated due to odd "100 nanoseconds as unit" part but technically doable.

I'd be happy to help with a PR if anyone is interested in adding this.

gabrielbalan commented 1 year ago

Thank you for the quick reply.

Calculation for version 1 is bit more complicated due to odd "100 nanoseconds as unit" part but technically doable. Not sure I understand.

I would expect that for version 1, one could just use java.util.UUID#timestamp() .

As for going from "100s of nanos since gregorian epoch" to "millis since unix epoch", how about this:

(timestamp - UUIDTimer.kClockOffset)/10_000;

cowtowncoder commented 1 year ago

If I read Javadocs for UUID#timestamp() correctly:

The 60 bit timestamp value is constructed from the time_low, time_mid, and time_hi fields of this UUID. The resulting timestamp is measured in 100-nanosecond units since midnight, October 15, 1582 UTC. 

it does NOT give value comparable to System.currentTimeMillis() but the raw 100-nsec-unit value?

This is fine, of course, UUIDUtil could/should have two methods: one for "raw" timestamp (in whatever base, units, version uses), and another "normalized" for "milliseconds since 1970-01-01/Z". Latter usually more relevant but presumably former too.

Then there are questions of what to do with ones that have no timestamp; either return 0L, use Optional<Long> return type, or throw exception.

gabrielbalan commented 1 year ago

Hi, thank you for taking the time.

Right, UUID.timestamp() shuffles the MSB of UUIDv1 and returns the number of "100-nanosecond units since midnight, October 15, 1582 UTC." (lets call that gregorian epoch)

So my original ask was for the equivalent of UUID.timestamp() for UUIDv6. That's why I used the term timestamp.

But ultimately I want the milliseconds since unix epoch, for which it seems the conversion is:

(timestamp - UUIDTimer.kClockOffset)/10_000;

I don't really need the "100-nanosecond units since gregorian epoch", I only asked for it because UUIDv1 and UUIDv6 have different conversions from MSB to "100-nanosecond units since gregorian epoch", and then the same conversion from that to "millis since unix epoch".

Then there are questions of what to do with ones that have no timestamp; either return 0L, use Optional return type, or throw exception.

my 2c: UUID.timestamp() throws UnsupportedOperationException. If only for this reason I would do the same.

cowtowncoder commented 1 year ago

Sounds good. If anyone has time and interest to work on this, I'm happy to help getting it done.