15

I need to create a timestamp (in milliseconds) in Java that is guaranteed to be unique in that particular VM-instance. I.e. need some way to throttle the throughput of System.currentTimeMillis() so that it returns at most one results every ms. Any ideas on how to implement that?

Yrlec
  • 3,401
  • 6
  • 39
  • 75
  • 2
    I'm not sure what do you mean *throttling* currentTimeMillis() so that it returns *at most* one result every ms? If you want unique timestamps, you'd rather like to guarantee that it returns a different value at each call, right? – Joonas Pulakka Feb 08 '12 at 10:16
  • Do they have to be monotonically increasing? Do they have to bear any relationship with actual *time*? Do they have to be unique across multiple runs at all? – Jon Skeet Feb 08 '12 at 10:17

5 Answers5

43

This will give a time as close the current time as possible without duplicates.

private static final AtomicLong LAST_TIME_MS = new AtomicLong();
public static long uniqueCurrentTimeMS() {
    long now = System.currentTimeMillis();
    while(true) {
        long lastTime = LAST_TIME_MS.get();
        if (lastTime >= now)
            now = lastTime+1;
        if (LAST_TIME_MS.compareAndSet(lastTime, now))
            return now;
    }
}

One way to avoid the limitation of one id per milli-second is to use a micro-second timestamp. i.e. multiply currentTimeMS by 1000. This will allow 1000 ids per milli-second.

Note: if time goes backwards, eg due to an NTP correction, the time will just progress at 1 milli-second per invocation until time catches up. ;)

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Used correctly, this will mean you will have unique ids even after restarting your application. – Peter Lawrey Feb 08 '12 at 10:32
  • 3
    You don't exceed an average of 1 per milli-second or 1000 per milli-second (depending on what your multiple is) This way by the time you restart, the id will be greater than the last id used before the application stopped. Given you can make the factor anything you want, this shouldn't be a problem. I use a nano-time basic id. ;) – Peter Lawrey Feb 08 '12 at 10:52
4

You can use System.nanoTime() for better accuracy

Although I tried below and each time it gives different values, it probably is not guaranteed to be unique all the time.

public static void main(String[] args) {
        long time1 = System.nanoTime();
        long time2 = System.nanoTime();
        long time3 = System.nanoTime();
        System.out.println(time1);
        System.out.println(time2);
        System.out.println(time3);
    }

Another way is to use AtomicInteger/AtomicLong classes for unique numbers if the time is not important for you and you just need unique number, this probably is a btter choice.

fmucar
  • 14,361
  • 2
  • 45
  • 50
  • 3
    nanoTime is monotonic, but not always unique. You can get lots of duplicates. e.g. on Red Hat & Centos 5.x the resolution is micro-second, so you get lots of repeated values. – Peter Lawrey Feb 08 '12 at 10:33
  • Thanks for the info. I guessed it depends on the OS and the machine. – fmucar Feb 08 '12 at 11:40
  • 1
    You can use nanoTime with a check that its different. (Similar to my solution) The nanoTime is the uptime in ano-seconds on many systems. – Peter Lawrey Feb 08 '12 at 12:01
  • +1: Done the same for you answer as you can use nanoTime with AtomicLong (not AtomicInteger) – Peter Lawrey Feb 08 '12 at 15:16
2

While searching for a solution I came across ULIB (Universally Unique Lexicographically Sortable Identifier) https://github.com/huxi/sulky/tree/master/sulky-ulid/

It's not a long, but shorter then UUID.

A ULID:

  • Is compatible with UUID/GUID's 1.21e+24 unique ULIDs per millisecond (1,208,925,819,614,629,174,706,176 to be exact)
  • Lexicographically sortable
  • Canonically encoded as a 26 character string, as opposed to the 36 character UUID
  • Uses Crockford's base32 for better efficiency and readability (5 bits per character)
  • Case insensitive
  • No special characters (URL safe)
Marian Venin
  • 111
  • 1
  • 5
1

You could use System.nanoTime(), which is the most precise available system timer, and divide that by million to get milliseconds. While there are no formal guarantees on how often it's updated, I believe it's reasonable to assume that it updates way more (order(s) of magnitude) frequently than once per millisecond. Of course, if you create integer timestamps by less than millisecond interval, then they can't all be unique.

Note that the absolute value nanoTime() is arbitrary. If you want absolute time, calibrate it somehow, i.e. compare it to currentTimeMillis() when starting.

Joonas Pulakka
  • 36,252
  • 29
  • 106
  • 169
0

Could you perhaps make use of java.util.UUID and it's timestamp() and clockSequence()?

Method Summary
    int clockSequence() 
        The clock sequence value associated with this UUID.
    long timestamp() 
        The timestamp value associated with this UUID.

More details here: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/UUID.html