web-dev-qa-db-ja.com

Javaで経過時間を測定する方法

私はこのようなものが欲しいのです。

public class Stream
{
    public startTime;
    public endTime;

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

また、たとえばstartTimeが23:00でendTimeが1:00の場合、2:00の期間を取得することも重要です。

Javaでこれを達成するために使用するタイプはどれですか?

306
Omu

残念ながら、これまでに投稿された10の答えのどれも全く正しいものではありません。

経過時間を測定していて、それを correct にしたい場合は、System.nanoTime()を使用する必要があります。あなたの結果が間違っていることを気にしない限り、あなたはSystem.currentTimeMillis()を使うことはできません。

nanoTimeの目的は 経過 timeを測定することであり、currentTimeMillisの目的は wall-clock timeを測定することです。他の目的には使えません。その理由は、コンピュータの時計が完璧ではないからです。それは常にドリフトし、時折修正する必要があります。この修正は手動で行われるか、ほとんどのマシンの場合、実行されてシステムクロックに小さな修正(「ウォールクロック」)を継続的に発行するプロセスがあります。これらは頻繁に起こる傾向があります。うるう秒があるときはいつでもそのようなもう一つの修正が起こります。

nanoTimeの目的は経過時間を測定することですので、これらの小さな修正の影響を受けません。それはあなたが使いたいものです。 currentTimeMillisで現在進行中のすべてのタイミングはずれています - おそらくマイナスさえあります。

あなたは、「これはそれほど問題にならないでしょう」と言うかもしれませんが、全体的に言って、正しいコードは間違ったコードより優れているのではないでしょうか。それに、nanoTimeはとにかく入力が短いです。

通常マイクロ秒の精度しか持たないnanoTimeに関する以前に投稿された免責事項は有効です。また、状況によっては、呼び出しに1マイクロ秒以上かかることがあります(他の場合と同様)ので、非常に短い間隔を正しく計時しないでください。

611

Javaでこれを達成するために使用するタイプはどれですか?

簡単な答えはlongです。さて、測定方法の詳細...

System.currentTimeMillis()

これを行うための「伝統的な」方法は、実際に System.currentTimeMillis() を使用することです。

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

o.a.c.l.t.StopWatch

Commons Langには StopWatch クラスがあり、これを使用して実行時間をミリ秒単位で測定できます。 split()suspend()resume() などのようなメソッドメソッドがあり、実行のさまざまな時点で対策を講じることができ、便利かもしれません。それを見てください。

System.nanoTime()

非常に正確な経過時間の測定値を探しているのであれば、 System.nanoTime() を使うほうがよいでしょう。そのJavadocから:

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

ジャモン

もう一つの選択肢は JAMon 、start()の間に来るコードに対して statistics (実行時間、ヒット数、平均実行時間、最小、最大など)を集めるツールを使うことです。そしてstop()メソッド以下は、とても簡単な例です。

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

Niceの紹介はwww.javaperformancetunning.comで この記事 をチェックしてください。

AOPを使う

最後に、これらの測定値でコードを乱雑にしたくない場合(または既存のコードを変更できない場合)、AOPは完璧な武器になります。これについてはあまり深く議論するつもりはありませんが、少なくとも言及することを望みました。

以下は、AspectJとJAMonを使った非常に単純なアスペクトです(ここでは、ポイントカットの短い名前がJAMonモニタに使われるので、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の測定は本当に完璧なユースケースです。

202
Pascal Thivent

あなたの新しいクラス:

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

その後、経過した時間は、カレンダーなどを使って好きな形式に変換できます。

グリーツ、GHad

36
GHad

目的がプログラムログに単純なタイミング情報を単純に出力することである場合、Javaプロジェクトのための簡単な解決策はあなた自身のストップウォッチやタイマークラスを書くことではなく、単に 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);
19
David Bliss

tl; dr

たとえば、startTimeが23:00でendTimeが1:00の場合は、2:00の期間を取得します。

ありえない。時刻があるだけの場合、時計は真夜中に停止します。日付の文脈がなくても、翌日、来週、または今後10年間の午前1時を意味するのかどうか、どうやってわかりますか。

そのため、11 PMから午前1時の間は、時計の針を反時計回りに回しながら、22時間以内に後方を動かすことになります。下の結果、a negative 22時間を参照してください。

Duration.between(              // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
    LocalTime.of( 23 , 0 ) ,   // A time-of-day without a date and without a time zone. 
    LocalTime.of( 1 , 0 )      // A time-of-day clock stops at midnight. So getting to 1 AM from 11 PM means going backwards 22 hours.
)                              // Return a `Duration` object.
.toString()                    // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS

PT-22H

深夜0時を通過するには、時刻に加えて日付のより大きなコンテキストが必要です(下記参照)。

Javaで経過時間を測定する方法

  1. Instant.now() で、UTCで現在の瞬間をとらえてください。
  2. そのような瞬間をあとで捉えてください。
  3. 両方を Duration.between に渡してください。
  4. (a)結果のDurationオブジェクトから、さまざまなto…Partメソッドを呼び出して、24時間、日、時、分、秒、およびナノ秒単位の小数秒を抽出します。
    (b)または、toStringを呼び出して、Stringstandard ISO 8601フォーマットPnYnMnDTnHnMnSを生成します。

Instant オブジェクトのペアを使用したコード例。

Duration.between(    // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
    then ,           // Some other `Instant` object, captured earlier with `Instant.now()`.
    Instant.now()    // Capture the current moment in UTC with a resolution as fine as nanoseconds, depending on the limits of your Host computer hardware clock and operating system. Generally you will get current moment in microseconds (six decimal digits of fractional second) in Java 9, 10, and 11, but only milliseconds in Java 8. 
)                    // Return a `Duration` object.
.toString()          // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS

PT3M27.602197S

Java 8以降の新技術

このための新しい技術が、現在はJava 8以降に組み込まれており、 Java.time フレームワークです。

Java.time

Java.timeフレームワークは JSR 310 で定義されており、 ThreeTen-Extra プロジェクトによって拡張され、 Oracle Tutorial で説明されている、非常に成功した Joda-Time プロジェクトに触発されました。 ]。

Javaの初期のバージョンにバンドルされているJava.util.Date/.Calendarなどの古い日時クラスは、設計が不適切で、混乱しやすく、面倒です。それらはJava.timeクラスに取って代わられます。

解決

他の回答では、解決方法について説明しています。

Java.timeクラスの分解能は nanosecond で、最大9桁の10進数/ 1秒です。たとえば、2016-03-12T04:29:39.123456789Zです。

古いJava.util.Date/.CalendarクラスとJoda-Timeクラスはどちらもミリ秒の分解能(3桁の小数)を持っています。たとえば、2016-03-12T04:29:39.123Zです。

Java 8では、レガシーの問題のため、現在の瞬間が最大わずか1ミリ秒の解像度で取得されます。 Java 9以降では、コンピュータのハードウェアクロックが非常に細かく動作していれば、現在の時刻をナノ秒単位の解像度まで決定できます。

時刻

日付やタイムゾーンが欠けている時刻のみを本当に扱いたい場合は、 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は開始をマークし( 'Period'のように)、Tは年月日の部分を時分秒の部分から分離します。

クロッシングミッドナイト

残念ながら、真夜中に時計の交差点を周回するときには、時刻の処理は厄介です。 LocalTimeクラスは、あなたがその日の早い時点にさかのぼりたいと仮定することによってこれを処理します。

上記と同じコードを使用して23:00から01:00に進むと、負の22時間(PT-22H)になります。

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

早く:23:00後:01:00 |持続時間:PT-22H

日付時刻

午前0時に交差する場合は、時刻のみの値ではなく日付と時刻の値を使用することがおそらく理にかなっています。

タイムゾーン

タイムゾーンは日付にとって非常に重要です。そこで、3つの項目を指定します。(1)希望の日付、(2)希望の時刻、および(3)その日時を解釈するためのコンテキストとしてのタイムゾーンです。ここでは Montréal 領域のタイムゾーンを任意に選択します。

offset-from-UTC のみで日付を定義する場合は、 ZoneOffset と共に OffsetDateTime を使用してください。フルタイムゾーン(オフセットと夏時間などの異常を処理するための規則)がある場合は、 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時に指定します。

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

上記と同じ方法でDurationを計算します。今度はこの質問で予想される2時間を得ます。

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

夏時間

当面の日時に夏時間(DST)などの異常が含まれていた場合は、必要に応じてJava.timeクラスを調整します。詳細はクラスのドキュメントを読んでください。


Java.timeについて

Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、 Java.util.DateCalendar 、& SimpleDateFormat などの厄介な古い legacy 日時クラスに代わるものです。

Joda-Time プロジェクトは、現在 maintenanceモード になっており、 Java.time クラスへの移行を推奨しています。

詳細については、 Oracleチュートリアル を参照してください。そして多くの例と説明についてはStack Overflowを検索してください。仕様は JSR 310 です。

データベースと直接Java.timeオブジェクトを交換できます。 JDBC 4.2 以降に準拠した JDBCドライバ を使用してください。文字列もJava.sql.*クラスも必要ありません。

Java.timeクラスはどこで入手できますか?

  • Java SE 8 Java SE 9 Java SE 10 、およびそれ以降
    • ビルトイン。
    • バンドル実装の標準Java APIの一部。
    • Java 9では、いくつかのマイナーな機能と修正が追加されています。
  • Java SE 6 および Java SE 7
    • Java.time機能の多くは ThreeTen-Backport でJava 6と7にバックポートされています。
  • Android
    • Java.timeクラスのAndroidバンドル実装の最新バージョン。
    • 初期のAndroid(<26)では、 ThreeTenABP プロジェクトはThreeTen-Backport(前述)を適応させます。 ThreeTenABPの使い方… を参照してください。

ThreeTen-Extra プロジェクトはJava.timeを追加のクラスで拡張します。このプロジェクトは、Java.timeに将来追加される可能性があることを証明するものです。 IntervalYearWeekYearQuartermore など、便利なクラスがいくつかあります。

15
Basil Bourque

Javaは静的メソッドSystem.currentTimeMillis()を提供します。そしてそれは長い値を返すので、それは良い参考資料です。他の多くのクラスは、同様に長い 'timeInMillis'パラメータを受け入れます。

そして多くの人が Joda Time ライブラリを使って日付と時刻を計算する方が簡単だと思います。

7
Andreas_D

これをJavaで実現するために使用するタイプは?

答え :長い

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. 

それがあなたの最初の質問に対する私の直接の答えです。

最後の「注意」として、Joda Timeを使うことをお勧めします。それはあなたが必要とするものに適した interval クラスを含みます。

6
OscarRyz

それは注目に値します

  • System.currentTimeMillis()の精度は、高々1ミリ秒です。その価値はあるウィンドウズシステムでは16msになることがあります。それは200ns以下の代替品よりも低コストです。
  • System.nanoTime()は、ほとんどのシステムでマイクロ秒の精度しかなく、Windowsシステムでは100マイクロ秒だけジャンプすることがあります(つまり、表示されるほど正確ではない場合があります)。
  • カレンダーは時間を計算するための非常に高価な方法です。 (私はXMLGregorianCalendarとは別に考えることができます)時にはそれが最も適切な解決策ですが、あなたは長い時間間隔だけをすべきであることに注意してください。
6
Peter Lawrey

もしあなたがJavaの Calendar APIを使いたいのなら あなたはこれを試すことができます、

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

期間を処理する必要があるアプリケーションを作成している場合は、期間、 間隔 、および期間を処理するためのクラスがあるJoda-Timeをご覧ください。あなたのgetDuration()メソッドは、Joda-Time Intervalを返すことができるように見えます:

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);
}
3
David Bliss
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]: https://i.stack.imgur.com/hYo8y.png
  [2]: https://i.stack.imgur.com/xPjCK.png
2
Shiva Sagan

タイムスタンプをSystem.currentTimeMillis()から取得している場合は、時間変数はlongになります。

1
uckelman

これを使って:

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の期間を取得することも重要です。)

"else"の部分はそれを正しくすることができます

0
N. N

私はSOから盗んだものに基づいてフォーマット機能を構築しました。ログメッセージの内容を「プロファイリング」する方法が必要だったので、固定長期間のメッセージが必要でした。

public static String GetElapsed(long aInitialTime, long aEndTime, boolean aIncludeMillis)
{
  StringBuffer elapsed = new StringBuffer();

  Map<String, Long> units = new HashMap<String, Long>();

  long milliseconds = aEndTime - aInitialTime;

  long seconds = milliseconds / 1000;
  long minutes = milliseconds / (60 * 1000);
  long hours = milliseconds / (60 * 60 * 1000);
  long days = milliseconds / (24 * 60 * 60 * 1000);

  units.put("milliseconds", milliseconds);
  units.put("seconds", seconds);
  units.put("minutes", minutes);
  units.put("hours", hours);
  units.put("days", days);

  if (days > 0)
  {
    long leftoverHours = hours % 24;
    units.put("hours", leftoverHours);
  }

  if (hours > 0)
  {
    long leftoeverMinutes = minutes % 60;
    units.put("minutes", leftoeverMinutes);
  }

  if (minutes > 0)
  {
    long leftoverSeconds = seconds % 60;
    units.put("seconds", leftoverSeconds);
  }

  if (seconds > 0)
  {
    long leftoverMilliseconds = milliseconds % 1000;
    units.put("milliseconds", leftoverMilliseconds);
  }

  elapsed.append(PrependZeroIfNeeded(units.get("days")) + " days ")
      .append(PrependZeroIfNeeded(units.get("hours")) + " hours ")
      .append(PrependZeroIfNeeded(units.get("minutes")) + " minutes ")
      .append(PrependZeroIfNeeded(units.get("seconds")) + " seconds ")
      .append(PrependZeroIfNeeded(units.get("milliseconds")) + " ms");

  return elapsed.toString();

}

private static String PrependZeroIfNeeded(long aValue)
{
  return aValue < 10 ? "0" + aValue : Long.toString(aValue);
}

そしてテストクラス:

import Java.util.Calendar;
import Java.util.Date;
import Java.util.GregorianCalendar;

import junit.framework.TestCase;

public class TimeUtilsTest extends TestCase
{

  public void testGetElapsed()
  {
    long start = System.currentTimeMillis();
    GregorianCalendar calendar = (GregorianCalendar) Calendar.getInstance();
    calendar.setTime(new Date(start));

    calendar.add(Calendar.MILLISECOND, 610);
    calendar.add(Calendar.SECOND, 35);
    calendar.add(Calendar.MINUTE, 5);
    calendar.add(Calendar.DAY_OF_YEAR, 5);

    long end = calendar.getTimeInMillis();

    assertEquals("05 days 00 hours 05 minutes 35 seconds 610 ms", TimeUtils.GetElapsed(start, end, true));

  }

}
0
Buffalo

私は物事をタイミングするときにこのコードが有用であることがわかりました:

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;
}
0
Ray Tayek