【问题标题】:Calculate duration between two hours in Java在Java中计算两个小时之间的持续时间
【发布时间】:2017-11-15 18:06:12
【问题描述】:

我想计算 Java 中两个小时 (HH:mm:ss) 之间的时间差(持续时间)。在这里,我已经阅读了几个关于这个主题的主题,但我的问题有点不同。

我也无法使用Joda-Time

示例:

input values:    12:03:00 
                 00:00:00

expected output: 11:57:00

Сode:

public static void main(String[] args) throws ParseException {

    Scanner sc = new Scanner(System.in);
    String startTime = sc.next();
    String endTime = sc.next();

    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    Date d1 = sdf.parse(startTime);
    Date d2 = sdf.parse(endTime);
    long elapsed = d2.getTime() - d1.getTime();

    String hms = String.format("%02d:%02d:%02d",
        TimeUnit.MILLISECONDS.toHours(elapsed),
        TimeUnit.MILLISECONDS.toMinutes(elapsed) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(elapsed)),
        TimeUnit.MILLISECONDS.toSeconds(elapsed) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(elapsed)));

    if (elapsed > 0) {
        System.out.println(hms);
    } else {

        elapsed = elapsed * (-1); //otherwise, print hours with '-'

        String hms1 = String.format("%02d:%02d:%02d",
            TimeUnit.MILLISECONDS.toHours(elapsed),
            TimeUnit.MILLISECONDS.toMinutes(elapsed) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(elapsed)),
            TimeUnit.MILLISECONDS.toSeconds(elapsed) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(elapsed)));

        System.out.println(hms1);
    }
}

结果:

expected output: 11:57:00

actual output:   12:03:00 //that's the problem

【问题讨论】:

  • 请格式化您的代码缩进,使其清晰易读。
  • "'我也不能使用 JodaTime :/" 你可以使用 Java 8 吗?
  • 仅供参考,麻烦的旧日期时间类,如 java.util.Datejava.util.Calendarjava.text.SimpleTextFormat 现在是 legacy,被 Java 8 及更高版本中的 java.time 类所取代。见Tutorial by Oracle
  • 亲爱的投票者:请在投票的同时留下批评。计算一天中的时间和一天结束之间经过的时间是一个合理的问题。
  • 使用启用/模拟时间 24:00(一天结束时的午夜)并且还具有持续时间格式化功能的 API 时,您可以获得很多收益。使用我的库 Time4J 的简单示例,请参阅gist

标签: java date duration


【解决方案1】:

这是你想做的吗:

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

public class HourTest {
    public static void main(String[] args) throws Exception {
        LocalDateTime ldt1 = LocalDateTime.parse("2015-05-04T12:07:00");
        LocalDateTime ldt2 = LocalDateTime.parse("2015-05-04T00:00:00");

        long seconds = Math.abs(ChronoUnit.SECONDS.between(ldt1, ldt2));

        String hms = String.format("%02d:%02d:%02d", seconds / 3600, (seconds / 60) % 60, seconds % 60);

        // Prints 12:07:00. I tried it.
        System.out.println(hms);
    }
}

【讨论】:

  • 不,我很确定它不是。一方面, ChronoUnit.between 返回严格的小时数(意味着它会截断分钟等)
  • 谢谢,但我刚刚尝试过 12:07:00 和 00:00:00,而且它只是打印:00:00:00(我也尝试过第二天): )
  • 我按原样运行该程序,它会打印“12:07:00”
  • 好的,但是输出应该是:11:53:00
【解决方案2】:

这里的基本缺陷是您想要两次之间的 NEAREST 距离。当您构建日期对象时,即使您仅格式化 Hour:Minute:Second 它仍然存储日/月/年等...对于日期 12:03:00 和 00:00:00 它默认为同一天,所以从(午夜到中午)的差异是你第二天(中午到午夜)得到的。您的解决方案是检查时间是否小于 12(军事时间),如果是,则在当天添加 1。

这是你的做法:

    String t1 = "12:03:00";
    String t2 = "00:00:00";
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

    Date d1 = sdf.parse(t1);
    Date d2 = sdf.parse(t2);
    Calendar c1 = Calendar.getInstance();
    Calendar c2 = Calendar.getInstance();
    c1.setTime(d1);
    c2.setTime(d2);

    if(c2.get(Calendar.HOUR_OF_DAY) < 12) {
        c2.set(Calendar.DAY_OF_YEAR, c2.get(Calendar.DAY_OF_YEAR) + 1);
    }
    long elapsed = c2.getTimeInMillis() - c1.getTimeInMillis();

【讨论】:

  • 好的,但我只能使用几个小时作为输入:/
  • 我用解决方案编辑了我的答案。您可以保持输入相同。日期将默认为 1970 年 1 月 1 日。因此,上面的代码将使 00:00:00 日期发生在 1970 年 1 月 2 日。
  • 谢谢!完美!
  • ,我有最后一个问题。当我输入:00:00:00 和 00:00:00 时,程序会打印 24:00:00(这是正常的,因为第二天和'日历')。你有什么想法吗,我如何将输出更改为 00:00:00?也许在 if(c2.get(Calendar.HOUR_OF_DAY)
【解决方案3】:

tl;博士

Duration.between( 
    LocalTime.parse( "12:03:00" ) , 
    LocalTime.parse( "23:59:59.999999999" ) 
).plusNanos( 1 ).withNanos( 0 ) 

PT11H57M

使用一纳秒

现代方法使用 java.time 类。

关键是只有一天中的时间,没有午夜。因此,您显然打算在一天结束时使用的 00:00 实际上被解释为一天的开始。

一天结束前只有最后一纳秒。 LocalTime 为最后一个纳秒定义了一个常量:LocalTime.MAX = 23:59:59.999999999

由于您只关心整秒,我们可以利用小数秒。如果您的结束时间恰好是00:00:00,请替换为LocalTime.MAX。然后计算一个Duration 对象。您可以添加一个纳秒,然后通过将小数秒(纳秒)设置为零来截断生成的小数秒。

对于00:00:00 以外的结束时间,数学仍然有效。添加纳秒后,….000000001 将获得秒的小数部分,Duration::withNanos 将截断不需要的小数部分。

// This code assumes the inputs are *always* in whole seconds, without any fraction-of-second.

LocalTime start = LocalTime.parse( "12:03:00" );
LocalTime stop = LocalTime.parse( "00:00:00" );

if( stop.equals( LocalTime.MIN ) ) {
    stop = LocalTime.MAX ; // `23:59:59.999999999`
}

Duration d = Duration.between( start , stop );
d = d.plusNanos( 1 ).withNanos( 0 ) ;

System.out.println( "start/stop: " + start + "/" + stop );
System.out.println( "d: " + d );

看到这个code run live at IdeOne.com

PT11H57M

格式化

toString 的输出是标准的ISO 8601 formatDuration 类可以解析和生成这些字符串。

我强烈建议不要以时间样式表示时间跨度,HH:MM:SS。这是模棱两可的,并且在被人类阅读时经常会造成混淆。

但是,如果您坚持使用这种格式,则必须自己构建字符串。 Duration 类缺少在其他 java.time 类中看到的 format 方法。奇怪的是,这个类最初缺乏提取部分的方法,包括天数、小时数、分钟数、秒数和小数秒。请参阅this Question 进行讨论。 Java 9 带来了这样的方法,命名为to…Part

在使用 Java 8 时,我建议对 ISO 8601 格式的输出进行字符串操作。将 PT 替换为空字符串。如果有M,请将H 替换为冒号。如果有S,请将M 替换为冒号,将S 替换为空字符串。如果没有S,则将M 替换为空字符串。我相信您可以在 Stack Overflow 上找到此代码。

【讨论】:

  • 这是一个很棒的解决方案!现在我只需要将 PT11H57M 格式化为 11:53:00。谢谢!
  • @DeanTwit 请参阅底部的新部分以了解格式。
【解决方案4】:

您可以使用java.time.Duration,它以ISO-8601 standards 为蓝本,并作为JSR-310 implementation 的一部分引入Java-8Java-9 引入了一些更方便的方法。

演示:

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class Main {
    public static void main(String[] args) {
        LocalDate today = LocalDate.now();
        LocalTime startTime = LocalTime.parse("12:03:00");
        LocalTime endTime = LocalTime.parse("00:00:00");

        LocalDateTime startDateTime = today.atTime(startTime);
        LocalDateTime endDateTime = today.atTime(endTime);

        if (startDateTime.isAfter(endDateTime)) {
            endDateTime = endDateTime.with(LocalTime.MIN).plusDays(1).with(endTime);
        }

        Duration duration = Duration.between(startDateTime, endDateTime);
        // Default format
        System.out.println(duration);

        // Custom format
        // ####################################Java-8####################################
        String formattedDuration = String.format("%02d:%02d:%02d", duration.toHours(), duration.toMinutes() % 60,
                duration.toSeconds() % 60);
        System.out.println(formattedDuration);
        // ##############################################################################

        // ####################################Java-9####################################
        formattedDuration = String.format("%02d:%02d:%02d", duration.toHoursPart(), duration.toMinutesPart(),
                duration.toSecondsPart());
        System.out.println(formattedDuration);
        // ##############################################################################
    }
}

输出:

PT11H57M
11:57:00
11:57:00

Trail: Date Time 了解现代日期时间 API。

【讨论】:

    猜你喜欢
    • 2014-02-28
    • 1970-01-01
    • 1970-01-01
    • 2020-06-28
    • 2021-01-03
    • 2020-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多