java中的当前时间(以微秒为单位)
在Unix系统上,有没有办法在Java中获得微秒精度的时间戳? 像C的gettimeofday
函数。
不,Java没有这个能力。
它确实有System.nanoTime(),但是只是给出了一些以前已知的时间的偏移量。 所以,虽然你不能从这个绝对数字,你可以用它来测量纳秒(或更高)的准确度。
请注意,JavaDoc表示虽然这提供了纳秒精度,但这并不意味着纳秒精度。 所以采取一些适当的大模数的返回值。
你可以使用System.nanoTime()
:
long start = System.nanoTime(); // do stuff long end = System.nanoTime(); long microseconds = (end - start) / 1000;
以纳秒为单位的时间,但这是一个严格的相对的措施。 它没有绝对的意义。 它只是用于比较其他纳秒时间来衡量一些事情做了多长时间。
TL;博士
Java 9和更高版本:捕获当前时刻的分辨率高达纳秒。 那是9位小数。
Instant.now()
2017-12-23T12:34:56.123456789Z
限制为微秒,截断。
Instant.now().truncatedTo( ChronoUnit.MICROSECONDS );
2017-12-23T12:34:56.123456Z
细节
其他的答案在Java 8中有点过时了。
java.time
Java 8和更高版本带有java.time框架。 这些新类取代了最早版本的Java(例如java.util.Date/.Calendar和java.text.SimpleDateFormat)附带的有缺陷的date – 时间类。 该框架由JSR 310定义,受Joda-Time的启发,由ThreeTen-Extra项目扩展。
java.time中的类parsing为毫微秒 ,比旧的date时间类和Joda-Time使用的毫秒要细得多。 这个问题比微秒问题要好得多。
Clock
实现
尽pipejava.time类支持以纳秒为单位的数值,但这些类在纳秒中还没有生成值。 now()
方法使用与旧的date时间类System.currentTimeMillis()
相同的旧时钟实现。 我们在java.time中有新的Clock
接口,但接口的实现是相同的旧的毫秒时钟。
所以你可以格式化ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
的结果的文本表示,以查看小数秒的九个数字,但只有前三个数字将具有这样的数字:
2017-12-23T12:34:56.789000000Z
Java 9中的新时钟
Java 9的OpenJDK和Oracle实现有一个新的默认的Clock
实现,具有更好的粒度,高达java.time类的全纳秒能力。
查看OpenJDK问题, 提高java.time.Clock.systemUTC()的实现精度 。 这个问题已经成功实施。
2017-12-23T12:34:56.123456789Z
在使用macOS Sierra的MacBook Pro(Retina,15英寸,2013年末),我得到当前时刻(微秒)(小数点后六位数字)。
2017-12-23T12:34:56.123456
硬件时钟
请记住,即使有一个新的更好的Clock
实现,您的结果可能会因计算机而异。 Java依赖底层计算机硬件的时钟来了解当前时刻。
- 硬件时钟的分辨率差别很大。 例如,如果某台计算机的硬件时钟仅支持微秒级粒度,则任何生成的date时间值将只有小数点后六位数字,最后三位数字为零。
- 硬件时钟的精度差别很大。 仅仅因为一个时钟产生一个十进制小数部分的数字,这些数字可能是不准确的,只是近似值,从实际时间偏离primefaces钟读取的时间 。 换句话说,就是因为你看到一串数字在小数点右边并不意味着你可以相信这些读数之间的时间间隔是真实的。
正如其他海报已经指出, 您的系统时钟可能不会在几微秒内与实际的世界时间同步。 尽pipe如此,微秒精度时间戳还可以用作指示当前挂墙时间和测量/分析事物持续时间的混合。
我使用诸如“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) ; } }
如果你对Linux感兴趣:如果你把源代码弄到“currentTimeMillis()”,你会发现,在Linux上,如果你调用这个方法,它会得到微秒的时间。 然而Java然后截断微秒并且回传毫秒。 这部分是因为Java必须是跨平台的,因此提供专门针对Linux的方法是一个不容错过的日子(记住,从1.6向后的恶劣软链接支持?)。 这也是因为,虽然你的时钟可以让你在Linux回微秒,但这并不一定意味着它会检查时间。 在微秒级别,您需要知道NTP不会重新调整时间,并且在方法调用期间您的时钟没有漂移太多。
这意味着,在理论上,在Linux上,可以编写一个与System包中相同的JNI包装器,但不能截断微秒。
我最终select了一个“快速和肮脏”的解决scheme:
TimeUnit.NANOSECONDS.toMicros(System.nanoTime());
更新:
我最初用System.nanoTime去,但后来我发现它应该只用于经过的时间,我最终改变了我的代码工作在毫秒或在某些地方使用:
TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
但是这只会在值的末尾添加零(microsm = millis * 1000)
在这里留下这个答案作为一个“警告标志”,以防别人认为nanoTime 🙂
Java通过TimeUnit
枚举支持微秒。
这是Java文档: 枚举TimeUnit
你可以通过这种方式在java中获得微秒:
long microsenconds = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
您也可以将微秒转换回另一个时间单位,例如:
long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds);
如果你打算将它用于实时系统,也许java不是获得时间戳的最佳select。 但是如果你打算使用独特的钥匙,Jason Smith的答案就足够了。 但为了以防万一,预计2个项目最终会得到相同的时间戳(如果这两个项目几乎是同时处理的话,可能会发生这种情况),您可以循环,直到最后一个时间戳不等于当前时间戳为止。
String timestamp = new String(); do { timestamp = String.valueOf(MicroTimestamp.INSTANCE.get()); item.setTimestamp(timestamp); } while(lasttimestamp.equals(timestamp)); lasttimestamp = item.getTimestamp();
你也许可以创build一个组件来确定System.nanoTime()和System.currentTimeMillis()之间的偏移量,并且从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(); } }
以下testing在我的机器上产生相当好的结果。
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 ...
以下是如何创buildUnsignedLong当前时间戳的示例:
UnsignedLong current = new UnsignedLong(new Timestamp(new Date().getTime()).getTime());