在Unix系统上,是否有办法在Java中获得具有微秒级精度的时间戳?类似于C的gettimeofday
函数。
Instant.now()
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
在Unix系统上,是否有办法在Java中获得具有微秒级精度的时间戳?类似于C的gettimeofday
函数。
Instant.now()
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Answers:
不,Java没有该功能。
它确实具有System.nanoTime(),但是仅提供了一些先前已知时间的偏移量。因此,虽然您不能从中获取绝对数字,但可以使用它来测量纳秒(或更高)的精度。
请注意,JavaDoc表示,尽管这提供了纳秒级的精度,但这并不意味着纳秒级的精度。因此,取一些适当大的返回值模量。
Java 9和更高版本:捕获当前时刻时,分辨率高达纳秒。那是9位数的小数。
Instant.now()
2017-12-23T12:34:56.123456789Z
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
在实践中,您将看到用.now
现代传统计算机硬件时钟捕获的仅几微秒,而纳秒精度不高。
从Java 8开始,其他答案有些过时了。
Java 8和更高版本附带了java.time框架。这些新类取代了Java最早版本(例如java.util.Date/.Calendar和java.text.SimpleDateFormat)附带的有缺陷的麻烦的日期时间类。该框架由受Joda-Time启发,由ThreeTen-Extra项目扩展的JSR 310定义。
java.time中的类解析为纳秒,比旧的日期时间类和Joda-Time所使用的毫秒要细得多。并且比问题中要求的微秒更好。
Clock
实作尽管java.time类支持表示以纳秒为单位的值的数据,但这些类尚未生成以纳秒为单位的值。这些now()
方法使用与旧的日期时间类相同的旧时钟实现System.currentTimeMillis()
。我们Clock
在java.time中具有新接口,但是该接口的实现是相同的旧毫秒时钟。
因此,您可以设置结果的文本表示的格式,ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
以查看小数秒的9位数字,但是只有前3位数字会具有以下数字:
2017-12-23T12:34:56.789000000Z
Java 9的OpenJDK和Oracle实现具有Clock
粒度更细的新默认实现,最大可达java.time类的纳秒级能力。
请参见OpenJDK问题,提高java.time.Clock.systemUTC()的实现精度。该问题已成功实施。
2017-12-23T12:34:56.123456789Z
在装有macOS Sierra的MacBook Pro(15英寸,2013年末,视网膜)上,我得到的当前时刻以微秒为单位(最多十进制的六位数)。
2017-12-23T12:34:56.123456Z
请记住,即使采用新的更精细的Clock
实现,您的结果也可能因计算机而异。Java依靠底层计算机硬件的时钟来了解当前时刻。
Clock
。即便如此,在Java 8中,java.time类对于保留其他来源(例如,微秒)在Postgres数据库上捕获的值也很有帮助。但是要注意,微秒和纳秒范围内的值不准确;常见的计算机硬件可能无法准确地跟踪硬件时钟。六位数或九位数的小数秒的值可能不正确。
您可以使用System.nanoTime()
:
long start = System.nanoTime();
// do stuff
long end = System.nanoTime();
long microseconds = (end - start) / 1000;
可以获取时间(以纳秒为单位),但这是一个严格的相对度量。它没有绝对的意义。它仅用于与其他纳米时间进行比较以测量某项操作需要多长时间。
正如其他海报已经指出的那样;您的系统时钟可能未与实际世界时间同步最多微秒。尽管如此,微秒级精确时间戳还是可以用作混合信号,用于指示当前的墙壁时间以及测量/分析事物的持续时间。
我使用“ 2012-10-21 19:13:45.267128”之类的时间戳标记写入日志文件的所有事件/消息。这些既传送时它发生(“壁”的时间),并且还可以用于测量持续时间这一点,并在日志文件中的下一个事件(微秒相对差异)之间。
为此,您需要将System.currentTimeMillis()与System.nanoTime()链接起来,并从那一刻起专门与System.nanoTime()一起工作。示例代码:
/**
* 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) ;
}
}
MicroTimestamp.INSTANCE.get()
可能会出现问题。
get()
方法中没有更新成员变量的内容。它仅使用临时局部变量。
您可能会创建一个组件,该组件确定System.nanoTime()和System.currentTimeMillis()之间的偏移量,并有效地获得自纪元以来的纳秒。
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();
}
}
以下测试在我的机器上产生了相当不错的结果。
final Timer timer = new TimerImpl();
while (true) {
System.out.println(timer.nowNano());
System.out.println(timer.nowMilli());
}
差异似乎在+ -3ms的范围内振荡。我想可以再进一步调整偏移量计算。
1495065607202174413
1495065607203
1495065607202177574
1495065607203
...
1495065607372205730
1495065607370
1495065607372208890
1495065607370
...
如果您对Linux感兴趣:如果将源代码输出到“ currentTimeMillis()”,则会看到,在Linux上,如果调用此方法,则可以返回一微秒的时间。但是,Java随后会截断微秒,并将您递回毫秒。部分原因是因为Java必须是跨平台的,因此提供专门用于Linux的方法在今天是不容错过的事情(还记得从1.6反向支持粗鲁的软链接吗?!)。这也是因为,尽管您的时钟可以在Linux中为您提供微秒级的信息,但这并不一定意味着它可以很好地检查时间。在微秒级别,您需要知道NTP不会重新调整您的时间,并且在方法调用期间时钟的漂移不会太大。
从理论上讲,这意味着在Linux上,您可以编写与System软件包中的JNI包装相同的JNI包装,但不能截断微秒。
我最终使用的“快速而肮脏的”解决方案:
TimeUnit.NANOSECONDS.toMicros(System.nanoTime());
更新:
我最初使用System.nanoTime,但是后来我发现它仅应用于经过的时间,最终我更改了代码以使其可以使用毫秒或在某些地方使用:
TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
但这只会在值的末尾添加零(微秒=毫秒* 1000)
如果有人想到nanoTime,则将此答案留在此处作为“警告信号” :)
Java通过TimeUnit
枚举支持微秒。
这是Java文档: Enum TimeUnit
您可以通过以下方式在Java中获得微秒:
long microsenconds = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
您还可以将微秒转换回另一个时间单位,例如:
long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds);
如果打算将其用于实时系统,那么java并不是获取时间戳的最佳选择。但是,如果您要使用if作为唯一密钥,那么Jason Smith的答案就足够了。但是,以防万一,可以预期2个项目最终获得相同的时间戳(如果这两个项目几乎同时被处理,则可能会循环播放),直到最后一个时间戳与当前时间戳不相等为止。
String timestamp = new String();
do {
timestamp = String.valueOf(MicroTimestamp.INSTANCE.get());
item.setTimestamp(timestamp);
} while(lasttimestamp.equals(timestamp));
lasttimestamp = item.getTimestamp();