Search code examples
javajava-8uuid

how to get TimeBasedUuID using fasterxml for a specific date or for 24hrs before


Hi I trying to generate the timeBasedUUID for previous day. But it's always returning teh UUID for current date.

My Code:

public static long getTimeFromUUID(UUID uuid) {
return (uuid.timestamp() - NUM_100NS_INTERVALS_SINCE_UUID_EPOCH) / 10000;
   }

public static void timeBasedGenerator() {
    try {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_MONTH, -1);
        UUIDTimer timer = new UUIDTimer(new Random(cal.getTimeInMillis()), null);
        TimeBasedGenerator uuidV1Generator = Generators.timeBasedGenerator(EthernetAddress.fromInterface(), timer);
        UUID uuid = uuidV1Generator.generate();
        System.out.println("uuid.toString() = " + uuid.toString());
        //UUID uuid = UUID.fromString(uuidString);
        long time = getTimeFromUUID(uuid);
        Date date = new Date(time);
        System.out.println(date);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Im using com.fasterxml.uuid dependency.

Thanks in advance


Solution

  • Example 1

    You can override the UUIDClock to return a date 24 hours before. The author explicitly allows overriding that class.

    This is an exemple using your code:

    package com.example;
    
    import java.io.IOException;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.Random;
    import java.util.UUID;
    
    import com.fasterxml.uuid.EthernetAddress;
    import com.fasterxml.uuid.Generators;
    import com.fasterxml.uuid.UUIDClock;
    import com.fasterxml.uuid.UUIDTimer;
    import com.fasterxml.uuid.impl.TimeBasedGenerator;
    
    public class MyUuidGenerator {
    
        public static class MyUUIDClock extends UUIDClock {
    
            private static final long A_DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
    
            /**
             * Returns the current time in milliseconds for 24 hours before.
             */
            @Override
            public long currentTimeMillis() {
                return System.currentTimeMillis() - A_DAY_IN_MILLISECONDS;
            }
        }
        
        private static final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 12219292800L * 10_000_000L;
    
        public static long getTimeFromUUID(UUID uuid) {
            return (uuid.timestamp() - NUM_100NS_INTERVALS_SINCE_UUID_EPOCH) / 10000;
        }
    
        public static void timeBasedGenerator() {
            try {
                Calendar cal = Calendar.getInstance();
                cal.add(Calendar.DAY_OF_MONTH, -1);
                MyUUIDClock clock = new MyUUIDClock(); // USING MY VERSION OF UUID CLOCK
                UUIDTimer timer = new UUIDTimer(new Random(cal.getTimeInMillis()), null, clock);
                TimeBasedGenerator uuidV1Generator = Generators.timeBasedGenerator(EthernetAddress.fromInterface(), timer);
                UUID uuid = uuidV1Generator.generate();
                System.out.println("uuid.toString() = " + uuid.toString());
                // UUID uuid = UUID.fromString(uuidString);
                long time = getTimeFromUUID(uuid);
                Date date = new Date(time);
                System.out.println(date);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        public static final void main(String[] args) {
    
            timeBasedGenerator();
        }
    }
    

    Example 2

    This example can generate UUIDs for specific time or for 24h before using fasterxml and java-8.

    package com.exemple;
    
    import java.time.Instant;
    import java.time.temporal.ChronoUnit;
    import java.util.UUID;
    
    import com.fasterxml.uuid.Generators;
    
    public class MyUuidGenerator {
    
        // 1582-10-15T00:00:00.000Z
        private static final long GREG_EPOCH = -12219292800L;
    
        private static final long TICK = 100; // 1 tick = 100ns
        private static final long TICKS_PER_SECOND = 10_000_000L;
    
        public static UUID getUuidForSpecificTime(Instant instant) {
            UUID uuid = Generators.timeBasedGenerator().generate();
            return setInstant(uuid, instant);
        }
    
        public static UUID getUuidFor24HoursBefore() {
            UUID uuid = Generators.timeBasedGenerator().generate();
            Instant instant = getInstant(uuid).minus(24, ChronoUnit.HOURS);
            return getUuidForSpecificTime(instant);
        }
    
        private static Instant getInstant(UUID uuid) {
            long timestamp = uuid.timestamp();
            long secs = (timestamp / TICKS_PER_SECOND) + GREG_EPOCH;
            long nano = (timestamp % TICKS_PER_SECOND) * TICK;
            return Instant.ofEpochSecond(secs, nano);
        }
    
        private static UUID setInstant(UUID uuid, Instant instant) {
            final long secs = instant.getEpochSecond() - GREG_EPOCH;
            final long nano = instant.getNano();
            final long ts = (secs * TICKS_PER_SECOND) + (nano / TICK);
            final long msb = (((ts >>> 48) & 0x0FFFL) | 0x1000) | (((ts >>> 32) & 0xFFFFL) << 16) | ts << 32;
            return new UUID(msb, uuid.getLeastSignificantBits());
        }
    
        public static final void main(String[] args) {
    
            // GENERATE UUID WITH CURRENT TIME
            UUID uuid1 = Generators.timeBasedGenerator().generate();
            Instant instant1 = getInstant(uuid1);
            System.out.println(String.format("CURRENT:    uuid='%s', instant='%s'", uuid1, instant1));
    
            // GENERATE UUID FOR 24 HOURS BEFORE
            UUID uuid2 = getUuidFor24HoursBefore();
            Instant instant2 = getInstant(uuid2);
            System.out.println(String.format("24H BEFORE: uuid='%s', instant='%s'", uuid2, instant2));
    
            // GENERATE UUID FOR SPECIFIC TIME
            UUID uuid3 = getUuidForSpecificTime(Instant.parse("1999-12-31T23:59:59.999999999Z"));
            Instant instant3 = getInstant(uuid3);
            System.out.println(String.format("SPEC TIME:  uuid='%s', instant='%s'", uuid3, instant3));
        }
    }
    

    Output:

    CURRENT:    uuid='f866cca9-11fc-11ec-a904-2b9a77798447', instant='2021-09-10T06:04:33.856016900Z'
    24H BEFORE: uuid='ce01044a-1133-11ec-a904-0549d5549f8b', instant='2021-09-09T06:04:33.882017Z'
    SPEC TIME:  uuid='63afffff-bfde-11d3-a904-8562adc72b58', instant='1999-12-31T23:59:59.999999900Z'
    

    If you can add another dependency to your project, maybe you can use uuid-creator. This is another example with 2 lines:

    Instant for24HoursBefore = Instant.now().minus(24, ChronoUnit.HOURS);
    UUID uuid = UuidCreator.getTimeBased(for24HoursBefore, null, null);