package org.argeo.api.uuid;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.UUID;
/**
* A time based UUID, whose content can therefore be usefully interpreted as
* time and node identifier information.
*/
public class TimeUuid extends TypedUuid {
private static final long serialVersionUID = APM.SERIAL;
/**
* Start of the Gregorian time on October 15th 1582, equivalent to
* {@link UUID#timestamp()} == 0
.
*/
public final static Instant TIMESTAMP_ZERO = ZonedDateTime.of(1582, 10, 15, 0, 0, 0, 0, ZoneOffset.UTC).toInstant();
/** Constructor based on a {@link UUID}. */
public TimeUuid(UUID uuid) {
super(uuid);
if (uuid.version() != 1 && uuid.variant() != 2)
throw new IllegalArgumentException("The provided UUID is not a time based UUID.");
}
/** {@link UUID#timestamp()} as an {@link Instant}. */
public final Instant getInstant() {
long timestamp = uuid.timestamp();
return TIMESTAMP_ZERO.plus(timestampDifferenceToDuration(timestamp));
}
/** {@link UUID#node()} as an hex string. */
public final String getNodeId() {
return Long.toHexString(uuid.node());
}
/** {@link UUID#clockSequence()} as an hex string. */
public final String getClockSequence() {
return Long.toHexString(uuid.clockSequence());
}
/**
* Always returns false
since time UUIDs are by definition not
* opaque.
*/
@Override
public final boolean isOpaque() {
return false;
}
/*
* STATIC UTILITIES
*/
/** Converts from duration in the time UUID timestamp format. */
public static Duration timestampDifferenceToDuration(long timestampDifference) {
long seconds = timestampDifference / 10000000;
long nano = (timestampDifference % 10000000) * 100;
return Duration.ofSeconds(seconds, nano);
}
/**
* A duration expressed in the time UUID timestamp format based on units of 100
* ns.
*/
public static long durationToTimestamp(Duration duration) {
return (duration.getSeconds() * 10000000 + duration.getNano() / 100);
}
/**
* An instant expressed in the time UUID timestamp format based on units of 100
* ns since {@link #TIMESTAMP_ZERO}.
*/
public static long instantToTimestamp(Instant instant) {
Duration duration = Duration.between(TimeUuid.TIMESTAMP_ZERO, instant);
return durationToTimestamp(duration);
}
/**
* Crate a time UUID with this instant as timestamp and clock and node id set to
* zero.
*/
public static UUID fromInstant(Instant instant) {
long timestamp = instantToTimestamp(instant);
long mostSig = toMostSignificantBits(timestamp);
UUID uuid = new UUID(mostSig, UuidFactory.LEAST_SIG_RFC4122_VARIANT);
return uuid;
}
/** Convert timestamp in UUID format to most significant bits of a time UUID. */
static long toMostSignificantBits(long timestamp) {
long mostSig = UuidFactory.MOST_SIG_VERSION1 | ((timestamp & 0xFFFFFFFFL) << 32) // time_low
| (((timestamp >> 32) & 0xFFFFL) << 16) // time_mid
| ((timestamp >> 48) & 0x0FFFL);// time_hi_and_version
return mostSig;
}
}