开发者

Current time in microseconds in java

开发者 https://www.devze.com 2022-12-10 21:43 出处:网络
On a Unix sys开发者_C百科tem, is there a way to get a timestamp with microsecond level accuracy in Java? Something like C\'s gettimeofday function.No, Java doesn\'t have that ability.

On a Unix sys开发者_C百科tem, is there a way to get a timestamp with microsecond level accuracy in Java? Something like C's gettimeofday function.


No, Java doesn't have that ability.

It does have System.nanoTime(), but that just gives an offset from some previously known time. So whilst you can't take the absolute number from this, you can use it to measure nanosecond (or higher) precision.

Note that the JavaDoc says that whilst this provides nanosecond precision, that doesn't mean nanosecond accuracy. So take some suitably large modulus of the return value.


tl;dr

Java 9 and later: Up to nanoseconds resolution when capturing the current moment. That’s 9 digits of decimal fraction.

Instant.now()   

2017-12-23T12:34:56.123456789Z

To limit to microseconds, truncate.

Instant                // Represent a moment in UTC. 
.now()                 // Capture the current moment. Returns a `Instant` object. 
.truncatedTo(          // Lop off the finer part of this moment. 
    ChronoUnit.MICROS  // Granularity to which we are truncating. 
)                      // Returns another `Instant` object rather than changing the original, per the immutable objects pattern. 

2017-12-23T12:34:56.123456Z

In practice, you will see only microseconds captured with .now as contemporary conventional computer hardware clocks are not accurate in nanoseconds.

Details

The other Answers are somewhat outdated as of Java 8.

java.time

Java 8 and later comes with the java.time framework. These new classes supplant the flawed troublesome date-time classes shipped with the earliest versions of Java such as java.util.Date/.Calendar and java.text.SimpleDateFormat. The framework is defined by JSR 310, inspired by Joda-Time, extended by the ThreeTen-Extra project.

The classes in java.time resolve to nanoseconds, much finer than the milliseconds used by both the old date-time classes and by Joda-Time. And finer than the microseconds asked in the Question.

Current time in microseconds in java

Clock Implementation

While the java.time classes support data representing values in nanoseconds, the classes do not yet generate values in nanoseconds. The now() methods use the same old clock implementation as the old date-time classes, System.currentTimeMillis(). We have the new Clock interface in java.time but the implementation for that interface is the same old milliseconds clock.

So you could format the textual representation of the result of ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ) to see nine digits of a fractional second but only the first three digits will have numbers like this:

2017-12-23T12:34:56.789000000Z

New Clock In Java 9

The OpenJDK and Oracle implementations of Java 9 have a new default Clock implementation with finer granularity, up to the full nanosecond capability of the java.time classes.

See the OpenJDK issue, Increase the precision of the implementation of java.time.Clock.systemUTC(). That issue has been successfully implemented.

2017-12-23T12:34:56.123456789Z

On a MacBook Pro (Retina, 15-inch, Late 2013) with macOS Sierra, I get the current moment in microseconds (up to six digits of decimal fraction).

2017-12-23T12:34:56.123456Z

Hardware Clock

Remember that even with a new finer Clock implementation, your results may vary by computer. Java depends on the underlying computer hardware’s clock to know the current moment.

  • The resolution of the hardware clocks vary widely. For example, if a particular computer’s hardware clock supports only microseconds granularity, any generated date-time values will have only six digits of fractional second with the last three digits being zeros.
  • The accuracy of the hardware clocks vary widely. Just because a clock generates a value with several digits of decimal fraction of a second, those digits may be inaccurate, just approximations, adrift from actual time as might be read from an atomic clock. In other words, just because you see a bunch of digits to the right of the decimal mark does not mean you can trust the elapsed time between such readings to be true to that minute degree.


You can use System.nanoTime():

long start = System.nanoTime();
// do stuff
long end = System.nanoTime();
long microseconds = (end - start) / 1000;

to get time in nanoseconds but it is a strictly relative measure. It has no absolute meaning. It is only useful for comparing to other nano times to measure how long something took to do.


As other posters already indicated; your system clock is probably not synchronized up to microseconds to actual world time. Nonetheless are microsecond precision timestamps useful as a hybrid for both indicating current wall time, and measuring/profiling the duration of things.

I label all events/messages written to a log files using timestamps like "2012-10-21 19:13:45.267128". These convey both when it happened ("wall" time), and can also be used to measure the duration between this and the next event in the log file (relative difference in microseconds).

To achieve this, you need to link System.currentTimeMillis() with System.nanoTime() and work exclusively with System.nanoTime() from that moment forward. Example code:

/**
 * Class to generate timestamps with microsecond precision
 * For example: MicroTimestamp.INSTANCE.get() = "2012-10-21 19:13:45.267128"
 */ 
public enum MicroTimestamp 
{  INSTANCE ;

   private long              startDate ;
   private long              startNanoseconds ;
   private SimpleDateFormat  dateFormat ;

   private MicroTimestamp()
   {  this.startDate = System.currentTimeMillis() ;
      this.startNanoseconds = System.nanoTime() ;
      this.dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") ;
   }

   public String get()
   {  long microSeconds = (System.nanoTime() - this.startNanoseconds) / 1000 ;
      long date = this.startDate + (microSeconds/1000) ;
      return this.dateFormat.format(date) + String.format("%03d", microSeconds % 1000) ;
   }
}


You could maybe create a component that determines the offset between System.nanoTime() and System.currentTimeMillis() and effectively get nanoseconds since epoch.

public class TimerImpl implements Timer {

    private final long offset;

    private static long calculateOffset() {
        final long nano = System.nanoTime();
        final long nanoFromMilli = System.currentTimeMillis() * 1_000_000;
        return nanoFromMilli - nano;
    }

    public TimerImpl() {
        final int count = 500;
        BigDecimal offsetSum = BigDecimal.ZERO;
        for (int i = 0; i < count; i++) {
            offsetSum = offsetSum.add(BigDecimal.valueOf(calculateOffset()));
        }
        offset = (offsetSum.divide(BigDecimal.valueOf(count))).longValue();
    }

    public long nowNano() {
        return offset + System.nanoTime();
    }

    public long nowMicro() {
        return (offset + System.nanoTime()) / 1000;
    }

    public long nowMilli() {
        return System.currentTimeMillis();
    }
}

Following test produces fairly good results on my machine.

    final Timer timer = new TimerImpl();
    while (true) {
        System.out.println(timer.nowNano());
        System.out.println(timer.nowMilli());
    }

The difference seems to oscillate in range of +-3ms. I guess one could tweak the offset calculation a bit more.

1495065607202174413
1495065607203
1495065607202177574
1495065607203
...
1495065607372205730
1495065607370
1495065607372208890
1495065607370
...


Use Instant to compute microseconds since Epoch:

val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;


a "quick and dirty" solution that I eventually went with:

TimeUnit.NANOSECONDS.toMicros(System.nanoTime());

UPDATE:

I originally went with System.nanoTime but then I found out it should only be used for elapsed time, I eventually changed my code to work with milliseconds or at some places use:

TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

but this will just add zeros at the end of the value (micros = millis * 1000)

Left this answer here as a "warning sign" in case someone else thinks of nanoTime :)


If you're interested in Linux: If you fish out the source code to "currentTimeMillis()", you'll see that, on Linux, if you call this method, it gets a microsecond time back. However Java then truncates the microseconds and hands you back milliseconds. This is partly because Java has to be cross platform so providing methods specifically for Linux was a big no-no back in the day (remember that cruddy soft link support from 1.6 backwards?!). It's also because, whilst you clock can give you back microseconds in Linux, that doesn't necessarily mean it'll be good for checking the time. At microsecond levels, you need to know that NTP is not realigning your time and that your clock has not drifted too much during method calls.

This means, in theory, on Linux, you could write a JNI wrapper that is the same as the one in the System package, but not truncate the microseconds.


Java support microseconds through TimeUnit enum.

Here is the java doc: Enum TimeUnit

You can get microseconds in java by this way:

long microsenconds = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

You also can convert microseconds back to another time units, for example:

long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds);


If you intend to use it for realtime system, perhaps java isnt the best choice to get the timestamp. But if youre going to use if for unique key, then Jason Smith's answer will do enough. But just in case, to anticipate 2 item end up getting the same timestamp (its possible if those 2 were processed almost simultaneously), you can loop until the last timestamp not equals with the current timestamp.

String timestamp = new String();
do {
    timestamp = String.valueOf(MicroTimestamp.INSTANCE.get());
    item.setTimestamp(timestamp);
} while(lasttimestamp.equals(timestamp));
lasttimestamp = item.getTimestamp();


LocalDateTime.now().truncatedTo(ChronoUnit.MICROS)


Here is an example of how to create an UnsignedLong current Timestamp:

UnsignedLong current = new UnsignedLong(new Timestamp(new Date().getTime()).getTime());
0

精彩评论

暂无评论...
验证码 换一张
取 消