我想要这样的东西:

public class Stream
{
    public startTime;
    public endTime;

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

同样重要的是,例如,如果startTime是23:00,endTime是1:00,则持续时间为2:00。

为了在Java中实现这一点,应该使用哪些类型?


当前回答

我建立了一个格式化函数,基于我偷来的东西。我需要一种方法来“分析”日志消息中的内容,所以我需要一个固定长度的持续时间消息。

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

  }

}

其他回答

如果你喜欢使用Java的日历API,你可以试试这个,

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

博士tl;

例如,如果startTime是23:00,endTime是1:00,则持续时间为2:00。

不可能的。如果你只有一天中的时间,时钟在午夜停止。如果没有日期的背景,我们怎么知道你说的是第二天凌晨1点,下一周,还是下一个十年?

所以从晚上11点到凌晨1点意味着时间倒退了22个小时,逆时针走时针。请看下面的结果,是负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

跨越午夜除了需要时间之外,还需要更大的日期上下文(见下文)。

如何在Java中测量时间流逝?

使用Instant.now()捕获UTC的当前时刻。 以后再捕捉这样的时刻。 将两者传递给Duration.between。 (a)从生成的Duration对象中,通过调用各种to…Part方法,提取24小时的天、小时、分、秒和以纳秒为单位的分数秒。

示例代码,使用一对即时对象。

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。时间框架由JSR 310定义,其灵感来自于非常成功的Joda-Time项目,由ThreeTen-Extra项目扩展,并在Oracle教程中进行了描述。

旧的日期时间类,如java.util.Date/。与早期版本的Java捆绑在一起的日历被证明设计得很糟糕,令人困惑,而且很麻烦。它们被爪哇取代了。时间类。

决议

其他答案讨论解决方案。

java。时间类具有纳秒分辨率,最高可达秒的小数部分的9位。例如:2016-03-12T04:29:39.123456789Z。

旧的java.util.Date/。Calendar类和Joda-Time类具有毫秒级分辨率(3位分数)。例如:2016-03-12T04:29:39.123Z。

在Java 8中,由于遗留问题,当前时刻只能以毫秒的分辨率获取。在Java 9及以后版本中,如果您的计算机硬件时钟运行得非常好,则可以以纳秒的分辨率确定当前时间。

1)

如果您确实希望只使用一天中的时间,而不使用任何日期或时区,请使用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 );

sooner: 17:00 | later: 19:00 | duration: 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

日期-时间

如果您打算越过午夜,那么使用日期时间值而不是仅使用日期时间值可能更有意义。

时区

时区对约会至关重要。因此,我们指定三个项目:(1)所需的日期,(2)所需的时间,以及(3)时区作为解释该日期和时间的上下文。这里我们任意选择Montréal区域的时区。

如果您仅通过从utc的偏移量定义日期,则使用带OffsetDateTime的ZoneOffset。如果您有一个完整的时区(偏移量加上处理异常(如日光节约时间)的规则),则使用ZoneId和zoneeddatetime。

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。现在我们有两个小时的时间来回答这个问题。

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。时间类别将根据需要调整。详细信息请阅读类文档。


关于java.time

java。时间框架内置于Java 8及更高版本中。这些类取代了麻烦的旧遗留日期-时间类,如java.util。日期,日历和简单日期格式。

Joda-Time项目现在处于维护模式,建议迁移到java。时间类。

要了解更多,请参阅Oracle教程。搜索Stack Overflow可以找到很多例子和解释。规范是JSR 310。

你可以交换java。Time对象直接使用数据库。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,不需要java。sql。*类。

从哪里获取java。时间类?

Java SE 8、Java SE 9、Java SE 10以及更高版本 内置的。 带有捆绑实现的标准Java API的一部分。 Java 9增加了一些小特性并进行了修复。 Java SE 6和Java SE 7 大部分的java。时间功能在ThreeTen-Backport中向后移植到Java 6和7。 安卓 后续版本的Android捆绑实现的java。时间类。 对于早期的Android (<26), ThreeTenABP项目适应ThreeTen-Backport(如上所述)。参见如何使用ThreeTenABP....

ThreeTen-Extra项目扩展了java。额外的课程时间。这个项目是未来可能添加到java.time的一个试验场。你可以在这里找到一些有用的类,比如Interval、YearWeek、YearQuarter等等。

你的新类:

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, 查德

不幸的是,目前发布的十个答案中没有一个是完全正确的。

如果您正在测量经过的时间,并且希望它是正确的,那么必须使用System.nanoTime()。您不能使用System.currentTimeMillis(),除非您不介意结果是错误的。

The purpose of nanoTime is to measure elapsed time, and the purpose of currentTimeMillis is to measure wall-clock time. You can't use the one for the other purpose. The reason is that no computer's clock is perfect; it always drifts and occasionally needs to be corrected. This correction might either happen manually, or in the case of most machines, there's a process that runs and continually issues small corrections to the system clock ("wall clock"). These tend to happen often. Another such correction happens whenever there is a leap second.

由于nanoTime的目的是测量经过的时间,因此它不受任何这些小修正的影响。它是你想要使用的。当前使用currentTimeMillis进行的任何计时都将关闭——甚至可能为负值。

您可能会说,“这听起来似乎并没有那么重要”,对此我说,也许不是,但总的来说,正确的代码不就是比错误的代码好吗?此外,nanoTime打字时间更短。

之前发布的关于nanoTime通常只有微秒精度的免责声明是有效的。此外,它可能需要超过一微秒的时间来调用,这取决于环境(另一个也是如此),所以不要期望对非常非常小的间隔进行正确的计时。

如果您正在编写一个必须处理持续时间的应用程序,那么请查看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);
}