计算Java / Groovy中的已用时间

时间:2009-02-19 23:03:40

标签: java date groovy

我有......


Date start = new Date()

...
...
...

Date stop = new Date()

我希望在这两个日期之间获得数年,数月,日,时,分和秒。

-

我会改进这个问题。

我只想把经过的时间作为一个绝对的衡量标准,不考虑闰年,每个月的日子等等。

因此,我认为过去几年和几个月都是不可能的,我能得到的只是天,小时,分钟和秒。

更具体地说,我想告诉某个任务持续到例如

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

请原谅我的精确度不足。

16 个答案:

答案 0 :(得分:91)

我刚刚发现了这个快速的Groovy源解决方案:

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

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

答案 1 :(得分:25)

你可以用division和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;

这应该会为您提供所需的所有信息。

编辑:由于人们似乎感到困惑,不,这不会考虑闰年或夏令时转换等因素。这是纯粹过去的时间,这是opensas要求的。

答案 2 :(得分:19)

使用标准Date API不太容易。

您可能希望改为Joda TimeJSR-310

我不是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());

答案 3 :(得分:10)

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

(不确定这是否有助于原始问题,但肯定是搜索者)。

答案 4 :(得分:6)

从Java 1.5开始,你应该使用TimeUnit.

这是一个简单的&简单的例子。我认为在groovy中它可能变得更短(一如既往)。

/**
 * 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";
}

哦,请避免多次退货;)

答案 5 :(得分:6)

实际上,关于Joda-Time的上述答案。

使用Joda-Time的Period课程有一种更简单的方法:

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

要自定义输出,请查看PeriodFormatPeriodFormatterPeriodFormatterBuilder类。

答案 6 :(得分:6)

TL;博士

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

使用java.time

现代方法使用java.time类来取代麻烦的旧日期时间类。

而不是Date,请使用InstantInstant类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。

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

使用Duration类连接时间线的时间跨度,分辨率为day-hours-minutes-seconds-nanos。

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

在解决了几年 - 几天的时间段内,请使用Period课程。

生成字符串为标准ISO 8601格式for durationsPnYnMnDTnHnMnSP标志着开始。 T将任何年 - 月 - 天与小时 - 分 - 秒分开。所以两个半小时是PT2H30M

String output = d.toString();

在Java 9及更高版本中,您可以使用方法toDaysParttoHoursPart等访问各个部分。

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 7 :(得分:3)

嗯,如果我得到你所要求的,你想知道如果:

开始= 2001年1月1日,上午10:00:00.000和

停止= 2003年1月6日,下午12:01:00.000

你想得到2年,0个月,5天,2小时,1分钟的答案

不幸的是,这是一个似是而非的答案。如果日期是1月2日和1月31日怎么办?那会是29天吗?好的,但是2月2日到3月2日是28(29)天,但会被列为1个月?

在不知道上下文的情况下,除了秒或可能天以外的任何时间长度都是可变的,因为月份和年份的长度不同。 2个日期之间的差异应该是静态单位,可以通过stop.getTime() - start.getTime()(这是毫秒的差异)很容易计算出来

答案 8 :(得分:3)

除了前面提到的 推荐的优秀JodaTime API之外,您可以使用的最佳标准Java替代方法是java.util.Calendar。使用它是麻烦的(这是一种保守措施......请看这里的单行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;
    }

}

它应该打印我现在的年龄=)

哦,我应该补充一下,您可以使用DateCalendar“转换”为Calendar#setTime()

答案 9 :(得分:1)

这很容易;您应该设置正确的时区

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

答案 10 :(得分:0)

创建Date对象毫无意义,因为所有这一切都包装了System.currentTimeMillis()。 getTime()函数只是解开Date对象。我建议你只需使用此功能即可获得很长时间。

如果你只需要第二个准确度,这很好。但是,如果您想要亚毫秒精度,请使用System.nanoTime()来获取经过的时间。

答案 11 :(得分:0)

这是我基于 Sebastian Celis 回答实施的完整功能。再次,从他的帖子 - ,这不会考虑像闰年或夏令时转换的事情。这是纯粹的经过时间

输出是根据我的需要量身定制的。这仅输出三个重要部分。而不是返回

  

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

答案 12 :(得分:0)

这是另一个类似的功能,如果需要,它不会显示天,小时,分钟等,如果不需要更改其文字。

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

}

答案 13 :(得分:0)

我通常这样做:

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将其分为所需的任何时间单位。

答案 14 :(得分:0)

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'
}

答案 15 :(得分:-1)

这是一个问题,需要考虑算法来计算闰年以及几年之后的确切月数和天数。有趣的是,如果只使用一个计量单位,它很简单。例如,两天之间的总天数是正确的,因为它与提醒天数相比,在数月和数年之后计算在二十年之内。

我目前正致力于从我的PML实现中提供它,例如,形式为:

unemployed <- date.difference[
    From = 2009-07-01, 
    Till = now, 
    YEARS, MONTHS, DAYS
]: yyyy-MM-dd

$$-> *unemployed -> date.translate[ YEARS, MONTHS, DAYS ] -> print["Unemployed for:", .]

当然,这对于精确的利率计算也很有用。