web-dev-qa-db-ja.com

Java / Groovyで経過時間を計算する

私が持っています...


Date start = new Date()

...
...
...

Date stop = new Date()

これら2つの日付の間に、年、月、日、時間、分、秒が経過したものを取得したいと思います。

-

質問を絞り込みます。

うるう年、各月の日などを考慮せずに、絶対的な測定値として経過時間を取得したいだけです。

したがって、年月を経過させることは不可能だと思います。取得できるのは、日、時間、分、秒だけです。

より具体的には、特定のタスクがたとえば.

20 sec
13 min, 4 sec
2 h, 10 min, 2 sec
4 d, 4 h, 2 min, 2 sec

だから、私の精度の欠如を許してください。

38
opensas

この簡単なGroovyソースソリューションを発見しました。

import groovy.time.TimeCategory 
import groovy.time.TimeDuration

TimeDuration td = TimeCategory.minus( stop, start )
println td
94
pd.

これはすべて、除算とmodで行えます。

long l1 = start.getTime();
long l2 = stop.getTime();
long diff = l2 - l1;

long secondInMillis = 1000;
long minuteInMillis = secondInMillis * 60;
long hourInMillis = minuteInMillis * 60;
long dayInMillis = hourInMillis * 24;

long elapsedDays = diff / dayInMillis;
diff = diff % dayInMillis;
long elapsedHours = diff / hourInMillis;
diff = diff % hourInMillis;
long elapsedMinutes = diff / minuteInMillis;
diff = diff % minuteInMillis;
long elapsedSeconds = diff / secondInMillis;

これで、要求したすべての情報が得られます。

編集:人々は混乱しているように見えるので、いや、これはうるう年や夏時間の切り替えなどを考慮に入れていません。それは純粋な経過ですtime、opensasが求めたものです。

25
Sebastian Celis

標準のDate APIではそれほど簡単ではありません。

代わりに Joda Time または JSR-31 をご覧ください。

私はJodaの専門家ではありませんが、コードは次のようになると思います。

Interval interval = new Interval(d1.getTime(), d2.getTime());
Period period = interval.toPeriod();
System.out.printf(
    "%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n", 
    period.getYears(), period.getMonths(), period.getDays(),
    period.getHours(), period.getMinutes(), period.getSeconds());
19
toolkit

JodaTimeに関しては、私はちょうどそれを始めました。それを提案したレスポンダーに感謝します。 Jodaコードのより凝縮されたバージョンを以下に示します。

Period period = new Period(d1.getTime(), d2.getTime());
System.out.printf(
    "%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n", 
    period.getYears(), period.getMonths(), period.getDays(),
    period.getHours(), period.getMinutes(), period.getSeconds());

(これが元の質問に役立つかどうかはわかりませんが、確かに検索者です)。

10
Fletch

tl; dr

Duration.between( then , Instant.now() )

Java.timeを使用する

最新の方法では、面倒な古い日時クラスに取って代わるJava.timeクラスを使用します。

Dateの代わりに、Instantを使用します。 Instant クラスは、 [〜#〜] utc [〜#〜] のタイムライン上の瞬間を ナノ秒 (最大9桁の解像度)で表します小数の)。

Instant then = Instant.now();
…
Instant now = Instant.now();

Duration クラスを使用して、タイムラインに関連付けられていない期間、day-hours-minutes-seconds-nanosの解像度を使用します。

Duration d = Duration.between( then , now );

年-月-日の解像度を持つ期間については、 Period クラスを使用します。

文字列の生成は標準です ISO 8601 形式 期間用PnYnMnDTnHnMnSPは開始を示します。 Tは、年、月、日、時間、分、秒を区切ります。したがって、2時間半はPT2H30Mです。

String output = d.toString();

Java9以降では、toDaysParttoHoursPartなどのメソッドを使用して個々のパーツにアクセスできます。

また、Java9以降ではInstant.nowが改善され、Javaで見られる ミリ秒 ではなく マイクロ秒 で現在の瞬間をキャプチャします。 8.もちろん、Javaのすべてのバージョンで、Instantクラスはholdの値を nanoseconds にできます。


Java.timeについて

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

Joda-Time プロジェクトは、現在 メンテナンスモード であり、 Java.time クラスへの移行を推奨しています。

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

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

  • Java SE 8 および SE 9 以降
    • ビルトイン。
    • バンドル実装を備えた標準JavaAPIの一部。
    • Java 9は、いくつかのマイナーな機能と修正を追加します。
  • Java SE 6 および SE 7
    • Java.time機能の多くは、 ThreeTen-Backport のJava6および7にバックポートされています。
  • Android

ThreeTen-Extra プロジェクトは、追加のクラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。ここでは、 IntervalYearWeekYearQuarter 、および more などの便利なクラスを見つけることができます。

6
Basil Bourque

Java 1.5を使用する必要があります TimeUnit。

これは簡単でわかりやすい例です。グルーヴィーでは(いつものように)短くなると思います。

/**
 * Formats a given {@link Date} to display a since-then timespan.
 * @param created
 * @return String with a format like "3 minutes ago"
 */
public static String getElapsedTime(Date created) {
    long duration = System.currentTimeMillis() - created.getTime();
    long seconds = TimeUnit.MILLISECONDS.toSeconds(duration);
    long days = TimeUnit.MILLISECONDS.toDays(duration);
    long hours = TimeUnit.MILLISECONDS.toHours(duration);
    long minutes = TimeUnit.MILLISECONDS.toMinutes(duration);
    if (days > 0) {
        return days + " days";
    }
    if (hours > 0) {
        return hours + " hrs";
    }
    if (minutes > 0) {
        return minutes + " minutes";
    }

    return seconds + " seconds";
}

ああ、複数のリターンを避けてください;)

6
dhesse

実際、 Joda-Time についての上記の回答に関して。

Joda-Timeの Period クラスでこれを行う簡単な方法があります。

Period period = new Period(startDate, endDate);
System.out.println(PeriodFormat.getDefault().print(period));

出力をカスタマイズするには、 PeriodFormatPeriodFormatter 、および PeriodFormatterBuilder クラスを調べます。

6
simao

前述の素晴らしい JodaTime APIとは別に、私doが推奨するAPI、最高の標準Java代わりに Java.util.Calendar を使用することもできますcumbersomeを使用する(これは控えめな表現です..行JodaTimeの例)、ただし経過時間も計算できます重要なキーは、ループでCalendar#add()を使用して、うるう日を取るために年、月、日の経過値を取得することです、年、世紀を考慮します(ミリ秒)から計算してはなりません。

基本的な例を次に示します。

import Java.util.Calendar;

public class Test {

    public static void main(String[] args) throws Exception {
        Calendar start = Calendar.getInstance();
        start.set(1978, 2, 26, 12, 35, 0); // Just an example.
        Calendar end = Calendar.getInstance();

        Integer[] elapsed = new Integer[6];
        Calendar clone = (Calendar) start.clone(); // Otherwise changes are been reflected.
        elapsed[0] = elapsed(clone, end, Calendar.YEAR);
        clone.add(Calendar.YEAR, elapsed[0]);
        elapsed[1] = elapsed(clone, end, Calendar.MONTH);
        clone.add(Calendar.MONTH, elapsed[1]);
        elapsed[2] = elapsed(clone, end, Calendar.DATE);
        clone.add(Calendar.DATE, elapsed[2]);
        elapsed[3] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 3600000;
        clone.add(Calendar.HOUR, elapsed[3]);
        elapsed[4] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 60000;
        clone.add(Calendar.MINUTE, elapsed[4]);
        elapsed[5] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 1000;

        System.out.format("%d years, %d months, %d days, %d hours, %d minutes, %d seconds", elapsed);
    }

    private static int elapsed(Calendar before, Calendar after, int field) {
        Calendar clone = (Calendar) before.clone(); // Otherwise changes are been reflected.
        int elapsed = -1;
        while (!clone.after(after)) {
            clone.add(field, 1);
            elapsed++;
        }
        return elapsed;
    }

}

現在の私の年齢を表示する必要があります=)

Calendar#setTime()を使用して、DateCalendarに「変換」できます。

3
BalusC

うーん、もし私があなたが求めているものを手に入れたら、あなたはそれを知りたい:

start = 2001年1月1日、午前10:00:00.000および

stop = 2003年1月6日、午後12:01:00.000 pm

2年、0か月、5日、2時間、1分の回答が必要な場合

残念ながら、これは正解です。日付が1月2日と1月31日だった場合はどうなりますか?それは29日でしょうか?わかりましたが、2月2日から3月2日は28(29)日ですが、1か月と表示されますか?

月と年は長さが異なるため、秒または場合によっては日以外の時間の長さは、コンテキストを知らなくても可変です。 2つの日付の差は静的な単位である必要があります。これは、stop.getTime()-start.getTime()(ミリ秒単位の差)から簡単に計算できます

3
billjamesdev

私はこれを一般的に行います:

def start_time = System.currentTimeMillis()
...
def end_time = System.currentTimeMillis()

println  (end_time - start_time) +' ms'

その後、Duration Groovyクラスを使用して、任意の時間単位に分割できます http://docs.groovy-lang.org/latest/html/api/groovy/time/Duration.html

1
Pablo Pazos

それは簡単です;適切なタイムゾーンを設定する必要があります

import Java.util.TimeZone;
import Java.util.logging.Logger;

import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class ImportData {

    private final static Logger log = Logger.getLogger(ImportData.class.getName());
    private final static DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
    private final static DateTimeFormatter dtfh = DateTimeFormat.forPattern("HH:mm:ss.SSS");

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
       TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
       DateTimeZone.setDefault(DateTimeZone.forID("Europe/Berlin"));
       // Quotes connection=Quotes.getInstance();
       final long start  = System.currentTimeMillis();
       // do something here ...
       // connection.importTickdata();
       Thread.currentThread().sleep(2000);
       final long end  = System.currentTimeMillis();
       log.info("[start]    " + dtf.print(start));
       log.info("[end]      " + dtf.print(end));
       TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
       DateTimeZone.setDefault(DateTimeZone.forID("UTC"));
       log.info("[duration] " + dtfh.print(end - start));
       // connection.logOff();
       // System.exit(0);
    }

戻り値:

 10.11.2010 00:08:12 ImportData main 
 INFO:[start] 2010-11-10 00:08:10.306 
 10.11.2010 00:08:12 ImportData main 
 INFO:[end] 2010-11-10 00:08:12.318 
 10.11.2010 00:08:12 ImportData main 
 INFO:[duration] 00:00:02.012 
1
udoline

これは別の同様の機能です。必要ない場合はリテラルを変更しなければ、日、時間、分などは表示されません。

public class ElapsedTime {

    public static void main(String args[]) {

        long start = System.currentTimeMillis();
        start -= (24 * 60 * 60 * 1000 * 2);
        start -= (60 * 60 * 1000 * 2);
        start -= (60 * 1000 * 3);
        start -= (1000 * 55);
        start -= 666;
        long end = System.currentTimeMillis();
        System.out.println(elapsedTime(start, end));

    }

    public static String elapsedTime(long start, long end) {

        String auxRet = "";

        long aux = end - start;
        long days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0;
        // days
        if (aux > 24 * 60 * 60 * 1000) {
            days = aux / (24 * 60 * 60 * 1000);
        }
        aux = aux % (24 * 60 * 60 * 1000);
        // hours
        if (aux > 60 * 60 * 1000) {
            hours = aux / (60 * 60 * 1000);
        }
        aux = aux % (60 * 60 * 1000);
        // minutes
        if (aux > 60 * 1000) {
            minutes = aux / (60 * 1000);
        }
        aux = aux % (60 * 1000);
        // seconds
        if (aux > 1000) {
            seconds = aux / (1000);
        }
        milliseconds = aux % 1000;

        if (days > 0) {
            auxRet = days + " days ";
        }
        if (days != 0 || hours > 0) {
            auxRet += hours + " hours ";
        }
        if (days != 0 || hours != 0 || minutes > 0) {
            auxRet += minutes + " minutes ";
        }
        if (days != 0 || hours != 0 || minutes != 0 || seconds > 0) {
            auxRet += seconds + " seconds ";
        }
        auxRet += milliseconds + " milliseconds ";

        return auxRet;
    }

}
0
jcgonzalez

これは、Sebastian Celis answerに基づいて実装した完全な関数です。そして再び、彼の投稿から-これはうるう年や夏時間の切り替えなどを考慮していません。純粋な経過時間です

出力は私のニーズに合わせて調整されています。これは、3つの重要なセクションのみを出力します。返す代わりに

4ヶ月、2週間、3日、7時間、28分、43秒

最初の3ブロックを返すだけです(投稿の最後に実行されるサンプルを参照してください)

4ヶ月、2週間、3日

メソッドの完全なソースコードを次に示します。

/**
 * Format milliseconds to elapsed time format
 * 
 * @param time difference in milliseconds
 * @return Human readable string representation - eg. 2 days, 14 hours, 5 minutes
 */
public static String formatTimeElapsedSinceMillisecond(long milisDiff) {
    if(milisDiff<1000){ return "0 second";}

    String formattedTime = "";
    long secondInMillis = 1000;
    long minuteInMillis = secondInMillis * 60;
    long hourInMillis = minuteInMillis * 60;
    long dayInMillis = hourInMillis * 24;
    long weekInMillis = dayInMillis * 7;
    long monthInMillis = dayInMillis * 30;

    int timeElapsed[] = new int[6];
    // Define time units - plural cases are handled inside loop
    String timeElapsedText[] = {"second", "minute", "hour", "day", "week", "month"};
    timeElapsed[5] = (int) (milisDiff / monthInMillis); // months
    milisDiff = milisDiff % monthInMillis;
    timeElapsed[4] = (int) (milisDiff / weekInMillis); // weeks
    milisDiff = milisDiff % weekInMillis;
    timeElapsed[3] = (int) (milisDiff / dayInMillis); // days
    milisDiff = milisDiff % dayInMillis;
    timeElapsed[2] = (int) (milisDiff / hourInMillis); // hours
    milisDiff = milisDiff % hourInMillis;
    timeElapsed[1] = (int) (milisDiff / minuteInMillis); // minutes
    milisDiff = milisDiff % minuteInMillis;
    timeElapsed[0] = (int) (milisDiff / secondInMillis); // seconds

    // Only adds 3 significant high valued units
    for(int i=(timeElapsed.length-1), j=0; i>=0 && j<3; i--){
        // loop from high to low time unit
        if(timeElapsed[i] > 0){
            formattedTime += ((j>0)? ", " :"") 
                + timeElapsed[i] 
                + " " + timeElapsedText[i] 
                + ( (timeElapsed[i]>1)? "s" : "" );
            ++j;
        }
    } // end for - build string

    return formattedTime;
} // end of formatTimeElapsedSinceMillisecond utility method

サンプルテストステートメントの例を次に示します。

System.out.println(formatTimeElapsedSinceMillisecond(21432424234L));
// Output: 8 months, 1 week, 1 day

System.out.println(formatTimeElapsedSinceMillisecond(87724294L));
// Output: 1 day, 22 minutes, 4 seconds

System.out.println(formatTimeElapsedSinceMillisecond(123434L));
// Output: 2 minutes, 3 seconds
0
Hossain Khan
import groovy.time.TimeCategory
import groovy.time.TimeDuration

time = { closure ->
    use(TimeCategory) {
        def started = new Date()
        def res = closure()
        TimeDuration duration = new Date() - started
        logger.info("Execution duration: " + duration.toMilliseconds() + "ms")
        res
    }
}

time {
    println 'A realy heavy operation here that you want to measure haha'
}

Dateオブジェクトを作成しても、System.currentTimeMillis()をラップするだけなので意味はありません。 getTime()関数は、Dateオブジェクトをラップ解除するだけです。この関数を使用してlongを取得することをお勧めします。

2番目の精度のみが必要な場合は、これで問題ありません。ただし、サブミリ秒の精度が必要な場合は、System.nanoTime()を使用して経過時間を取得します。

0
Peter Lawrey