1

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

Sooriya
  • 73
  • 1
  • 8
  • 2
    Since you are using Java 8 (tag), you could use `java.time` and classes like `LocalDate`, `ZonedDateTime` or similar with methods like `minusDays(long days)`. Don't stick to outdated APIs like `java.util.Date` and `java.util.Calendar`. – deHaar Sep 09 '21 at 12:32

1 Answers1

2

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);
fabiolimace
  • 972
  • 11
  • 13
  • can you explain the setInstant method in example 2 – Sooriya Apr 11 '22 at 16:41
  • The `setInstant()` method replaces the most significant bits of the input UUID with the specified instant. The input UUID does not have to be a time-based UUID. So you don't need to use the external library for that. You can just use `return setInstant(UUID.randomUUID(), instant)` and remove the external dependency. But if you want to continue with the dependency, maybe example 1 is better. – fabiolimace Apr 12 '22 at 19:35