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(); 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); } }