在Unix系统上,有没有办法在Java中获得具有微秒级精度的时间戳?类似C的gettimeofday
函数。
答案 0 :(得分:138)
不,Java没有这种能力。
它确实有System.nanoTime(),但这只是给出了一些先前已知时间的偏移量。因此,虽然您无法从中获取绝对数,但您可以使用它来测量纳秒(或更高)的精度。
请注意,JavaDoc表示虽然这提供了纳秒精度,但这并不意味着纳秒精度。因此,取一些适当大的返回值模数。
答案 1 :(得分:60)
Java 9及更高版本:捕获当前时刻时的分辨率高达纳秒。这是小数部分的9位数。
Instant.now()
2017-12-23T12:34:56.123456789Z
限制为microseconds,截断。
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
从Java 8开始,其他答案有点过时了。
Java 8及更高版本附带java.time框架。这些新类取代了最早版本的Java附带的有缺陷的麻烦的日期时间类,例如java.util.Date/.Calendar和java.text.SimpleDateFormat。该框架由JSR 310定义,受Joda-Time启发,由ThreeTen-Extra项目扩展。
java.time中的类解析为nanoseconds,比旧日期时间类和Joda-Time使用的milliseconds更精细。比问题中提到的microseconds更精细。
Clock
实施虽然java.time类支持表示以纳秒为单位的值的数据,但这些类还没有生成值,以纳秒为单位。 now()
方法使用与旧日期时间类System.currentTimeMillis()
相同的旧时钟实现。我们在java.time中有新的Clock
接口,但该接口的实现与旧的毫秒时钟相同。
因此,您可以格式化ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
结果的文本表示,以查看小数秒的九位数,但只有前三位数字会包含这样的数字:
2017-12-23T12:34:56.789000000Z
Java 9的OpenJDK和Oracle实现有一个新的默认Clock
实现,具有更精细的粒度,最高可达java.time类的完整纳秒级功能。
请参阅OpenJDK问题Increase the precision of the implementation of java.time.Clock.systemUTC()。该问题已成功实施。
2017-12-23T12:34:56.123456789Z
在使用macOS Sierra的MacBook Pro(Retina,15英寸,2013年末)上,我得到当前时刻,以微秒为单位(最多六位小数)。
2017-12-23T12:34:56.123456Z
请记住,即使使用更精细的Clock
实施,您的结果也可能因计算机而异。 Java依赖于底层计算机硬件的时钟来了解当前时刻。
答案 2 :(得分:54)
您可以使用System.nanoTime()
:
long start = System.nanoTime();
// do stuff
long end = System.nanoTime();
long microseconds = (end - start) / 1000;
以纳秒为单位获得时间,但这是一个严格的相对衡量标准。它没有绝对的意义。它仅用于与其他纳米时间进行比较,以衡量某些事情需要多长时间。
答案 3 :(得分:14)
正如其他海报已经表明的那样;您的系统时钟可能不会同步到微秒到实际世界时间。尽管如此,微秒精确时间戳可用作指示当前墙壁时间和测量/分析事物持续时间的混合物。
我使用“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) ;
}
}
答案 4 :(得分:2)
如果您对Linux感兴趣: 如果你将源代码变为“currentTimeMillis()”,你会发现,在Linux上,如果你调用这个方法,它会得到一个微秒的时间。然而,Java然后截断微秒并递回毫秒。这部分是因为Java必须是跨平台的,因此提供专门用于Linux的方法是当天的一个重要的禁忌(请记住,从1.6倒退的cruddy软链接支持?!)。这也是因为,虽然你的时钟可以在Linux中给你回微秒,但这并不一定意味着检查时间会很好。在微秒级别,您需要知道NTP没有重新调整您的时间,并且在方法调用期间您的时钟没有漂移太多。
这意味着,理论上,在Linux上,您可以编写一个与System包中的JNI包装相同的JNI包装器,但不会截断微秒。
答案 5 :(得分:2)
TimeUnit.NANOSECONDS.toMicros(System.nanoTime());
更新:
我最初使用的是System.nanoTime,但之后我发现它应该仅用于已用时间,我最终将代码更改为使用毫秒或在某些地方使用:
TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
但这只会在值的末尾添加零(micros = millis * 1000)
将此答案留在此处作为"警告标志"以防其他人想到nanoTime:)
答案 6 :(得分:2)
Java支持微秒到TimeUnit
枚举。
这是java doc: Enum TimeUnit
你可以通过这种方式在java中获得微秒:
long microsenconds = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
您还可以将微秒转换回另一个时间单位,例如:
long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds);
答案 7 :(得分:1)
您可以创建一个组件来确定System.nanoTime()和System.currentTimeMillis()之间的偏移量,并且自纪元以来有效地获得纳秒。
{
"comments": "App Insight Alert Rule",
"type": "microsoft.insights/alertrules",
"name": "[parameters('AppInsights.AlertRuleName')]",
"apiVersion": "2014-04-01",
"location": "East US",
"tags": {
"[concat('hidden-link:/subscriptions/',subscription().subscriptionId,'/resourcegroups/',parameters('ResourceGroupName'),'/providers/microsoft.insights/components/',parameters('AppInsights.Name'))]": "Resource"
},
"properties": {
"name": "[parameters('AppInsights.AlertRuleName')]",
"description": "",
"isEnabled": true,
"condition": {
"odata.type": "Microsoft.Azure.Management.Insights.Models.ThresholdRuleCondition",
"dataSource": {
"odata.type": "Microsoft.Azure.Management.Insights.Models.RuleMetricDataSource",
"resourceUri": "[resourceId('microsoft.insights/components', parameters('AppInsights.Name'))]",
"metricName": "requestFailed.count"
},
"threshold": 1,
"windowSize": "PT5M"
},
"action": {
"odata.type": "Microsoft.Azure.Management.Insights.Models.RuleEmailAction",
"customEmails": "[array(parameters('AppInsights.AlertSubscriber'))]"
}
},
"dependsOn": [
"[resourceId('microsoft.insights/components', parameters('AppInsights.Name'))]"
]
},
{
"type": "microsoft.insights/components",
"kind": "web",
"name": "[parameters('AppInsights.Name')]",
"apiVersion": "2014-04-01",
"location": "eastus",
"tags": {},
"properties": {
"ApplicationId": "[parameters('AppInsights.Name')]"
},
"dependsOn": []
},
{
"name": "[variables('billingplan')]",
"type": "microsoft.insights/components/CurrentBillingFeatures",
"location": "East US",
"apiVersion": "2015-05-01",
"dependsOn": [
"[resourceId('microsoft.insights/components', parameters('AppInsights.Name'))]"
],
"properties": {
"CurrentBillingFeatures": "[variables('pricePlan')]",
"DataVolumeCap": {
"Cap": "[parameters('AppInsights.DailyQuota')]"
}
}
}
]
}
以下测试在我的机器上产生相当好的结果。
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();
}
}
差异似乎在±3ms的范围内振荡。我想可以稍微调整偏移计算。
final Timer timer = new TimerImpl();
while (true) {
System.out.println(timer.nowNano());
System.out.println(timer.nowMilli());
}
答案 8 :(得分:0)
如果您打算将它用于实时系统,也许java不是获取时间戳的最佳选择。但是如果你要使用if作为唯一密钥,那么Jason Smith的答案就足够了。但是为了以防万一,为了预期2项最终得到相同的时间戳(如果这些2几乎同时处理,则可能),你可以循环直到最后一个时间戳不等于当前时间戳。
String timestamp = new String();
do {
timestamp = String.valueOf(MicroTimestamp.INSTANCE.get());
item.setTimestamp(timestamp);
} while(lasttimestamp.equals(timestamp));
lasttimestamp = item.getTimestamp();
答案 9 :(得分:0)
使用Instant来计算自纪元以来的微秒:
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
答案 10 :(得分:0)
LocalDateTime.now().truncatedTo(ChronoUnit.MICROS)
答案 11 :(得分:-3)
以下是如何创建UnsignedLong当前时间戳的示例:
UnsignedLong current = new UnsignedLong(new Timestamp(new Date().getTime()).getTime());