计算Java / Groovy中的已用时间

我有…

Date start = new Date() ... ... ... Date stop = new Date() 

我想在这两个date之间取得几年,几个月,几天,几小时,几分钟和几秒钟。

我会改进这个问题。

我只是想把时间花在绝对的时间上,而不考虑闰年,每个月的日子等。

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

更具体地说,我想告诉一个特定的任务持续了例如

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

所以请原谅我缺乏精确性。

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

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

你可以用分裂和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要求的。

标准的Date API不太容易。

你可能想看看Joda Time ,或者JSR-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()); 

关于JodaTime,我刚刚开始了。 感谢谁build议它的响应者。 下面是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()); 

(不知道这是否帮助原来的问题,但肯定是search者)。

那么从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"; } 

哦,请避免多个回报;)

其实,关于Joda-Time的上述回答。

Joda-Time's Period课程有一个更简单的方法:

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

要定制输出,请查看PeriodFormat , PeriodFormatter和PeriodFormatterBuilder类。

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

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

停止= 2003年1月6日,12:01:00

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

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

除了秒或可能的日子之外,时间的长度在不知道上下文的情况下是可变的,因为月和年的长度是不同的。 两个date之间的差异应该是静态单位,这可以很容易地从stop.getTime() – start.getTime()(这是以毫秒为单位的差异)

除了上面提到的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; } } 

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

哦,我应该补充一点,你可以使用Calendar#setTime()Date “转换”为Calendar

TL;博士

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

使用java.time

现代的方式使用取代麻烦的旧date时间类的java.time类。

使用Instant而不是DateInstant类表示UTC时间轴上的一个时刻,分辨率为纳秒 (最多九(9)位小数)。

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

使用“ Duration类别的时间范围未附加的一段时间,分辨率为日 – 分 – 秒 – 纳秒。

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

对于分辨率为年 – 月 – 日的时间段,使用Period类。

生成一个string是标准的ISO 8601格式持续时间 : PnYnMnDTnHnMnSP标志着开始。 T从几分钟到几秒将任意年 – 月 – 日分开。 所以两个半小时是PT2H30M

 String output = d.toString(); 

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


关于java.time

java.time框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧的遗留date时间类,如java.util.DateCalendarSimpleDateFormat

Joda-Time项目现在处于维护模式 ,build议迁移到java.time类。

要了解更多信息,请参阅Oracle教程 。 并search堆栈溢出了很多例子和解释。 规范是JSR 310 。

从何处获取java.time类?

  • Java SE 8SE 9及更高版本
    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小function和修复。
  • Java SE 6SE 7
    • 大部分的java.timefunction都被移植到了ThreeTen-Backport中的 Java 6&7中。
  • Android的
    • ThreeTenABP项目专门针对Android,采用了ThreeTen-Backport (上文提到)。
    • 请参阅如何使用ThreeTenABP …。

ThreeTen-Extra项目将java.time扩展到其他类。 这个项目是未来可能增加java.time的一个试验场。 你可能会在这里find一些有用的类,比如IntervalYearWeekYearQuarter 等等 。

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

 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主要
信息:[开始] 2010-11-10 00:08:10.306
 10.11.2010 00:08:12 ImportData主要
信息:[结束] 2010-11-10 00:08:12.318
 10.11.2010 00:08:12 ImportData主要
信息:[时间] 00:00:02.012

创build一个Date对象没有意义,因为所有这些都包装System.currentTimeMillis()。 getTime()函数只是展开Date对象。 我build议你只是使用这个函数来获得一个很长的。

如果你只需要第二个精度,这是好的。 但是,如果你想亚毫秒的准确性使用System.nanoTime()来获得stream逝的时间。

这是我根据塞巴斯蒂安·塞利斯答案实现的一个完整的function。 而且,从他的职位来看 – 这并不需要像闰年或夏令时那样的考虑。 这是纯粹的时间

产量是根据我的需求量身定做的。 这只输出三个有意义的部分。 而不是返回

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 

以下是一些示例testing语句:

 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 

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

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

这是一个问题,需要一个algorithm来解释闰年和几年和几年的确切数量。 有趣的是,如果只使用一个单位的度量,那么这很简单。 例如,两天之间的总天数是正确的,因为提醒天数在几个月和几年之后的天数是在二十年之内计算的。

我目前正在从这个PML实现中提供它,例如,以下面的forms:

 unemployed <- date.difference[ From = 2009-07-01, Till = now, YEARS, MONTHS, DAYS ]: yyyy-MM-dd $$-> *unemployed -> date.translate[ YEARS, MONTHS, DAYS ] -> print["Unemployed for:", .] 

当然,这对于确切的利率计算也是有用的和必需的。