java中的当前时间(以微秒为单位)

时间:2009-11-11 00:25:40

标签: java timestamp

在Unix系统上,有没有办法在Java中获得具有微秒级精度的时间戳?类似C的gettimeofday函数。

12 个答案:

答案 0 :(得分:138)

不,Java没有这种能力。

它确实有System.nanoTime(),但这只是给出了一些先前已知时间的偏移量。因此,虽然您无法从中获取绝对数,但您可以使用它来测量纳秒(或更高)的精度。

请注意,JavaDoc表示虽然这提供了纳秒精度,但这并不意味着纳秒精度。因此,取一些适当大的返回值模数。

答案 1 :(得分:60)

TL;博士

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.time

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更精细。

enter image description here

Clock实施

虽然java.time类支持表示以纳秒为单位的值的数据,但这些类还没有生成值,以纳秒为单位。 now()方法使用与旧日期时间类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问题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依赖于底层计算机硬件的时钟来了解当前时刻。

  • 硬件时钟的分辨率差别很大。例如,如果特定计算机的硬件时钟仅支持microseconds粒度,则任何生成的日期时间值将只有六位小数秒,后三位数为零。
  • 硬件时钟的准确度差别很大。仅仅因为时钟生成一个带有几位十进制小数位的值,这些数字可能是不准确的,只是近似值,可以从atomic clock读取的实际时间漂移。换句话说,仅仅因为你看到小数点右边的一串数字并不意味着你可以相信这些读数之间经过的时间对于那个分钟度是真实的。

答案 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)

快速而又肮脏的#34;我最终选择的解决方案:

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());