【问题标题】:Math.min Military Time vs Base 8 [duplicate]Math.min 军事时间与 Base 8 [重复]
【发布时间】:2020-10-03 05:33:21
【问题描述】:

我正在制作一个程序,旨在通过军事时间获取经过的时间,这就是我到目前为止得到的:

public class TimeInterval {
    private int firstTime;
    private int secondTime;

    public TimeInterval(int _first,int _second) {
        if (_first < 0 || _second < 0) {
            System.out.println("ERROR INVALID INPUT");
            System.exit(0);
        }
        else if (_first > 2400 || _second > 2400) {
            System.out.println("ERROR INVALID INPUT");
            System.exit(0); 
        }
        else
            firstTime = Math.max(_first, _second);
            secondTime = Math.min(_first,_second);
        }
    }

    public int getHours() {
        return (Integer.parseInt(Integer.toString(firstTime).substring(0, 2)))-(Integer.parseInt(Integer.toString(secondTime).substring(0, 2)));
    }
}

除了处理从 0000 到 0700 的 _first 或 _second 输入外,该程序大部分时间都可以工作。想法是它们被读取为军事时间,但 java 将它们读取为基数 8 整数,因此当 _first = 0700 和 _second = 1400 我得到 448 或其他东西。无论如何我可以确保当 _first 和 _second 输入到 Math.min 时,它们被读取为基数 10 而不是基数 8。

【问题讨论】:

  • 为什么将时间存储为int?您应该将时间存储为LocalTime
  • 问题不在Math.min。问题甚至不在此代码中。问题很可能出在您测试此代码的方式上。 Java 整数文字0700 实际上表示 448。前导零使其成为八进制文字。请注意,这仅适用于文字,而不适用于使用(例如)Integer.parseInt 转换为整数的字符串。
  • 但要注意的另一件事是“0700”在概念上不是整数。实际上是“07”小时+“00”分钟;即两个整数。所以概念上正确的表示它的方法是Java字符串;即"0700".
  • @StephenC 或者更正确的是,两个整数。然后你也可以从 java.time 到LocalTime
  • 这是真的....

标签: java math octal timeofday military


【解决方案1】:

您似乎假设军事时间始终是 4 位数字,并带有适当数量的前导零,从 0000 到 2359。您不能在 int 中表示军事时间的这个概念,因为 int 不一定有 4位数。相同的数字可以格式化为 6、06、006、0006 或 000000006。在内部它只是相同的 32 位。因此,当firstTime 为 700(或 0700)时,Integer.toString(firstTime).substring(0, 2)) 取 700 的前两位并产生 70(不是 7)。所以new TimeInterval(700, 1400).getHours() 产生 -56(不是 7)。如果firstTime 等于或小于9 (0009),您的代码可能会因StringIndexOutOfBoundsException 而崩溃。

一种解决方案是将您的军事时间传递到始终长度为 4 的 String 中。然后您的子字符串操作将始终采用前 2 位数字,即小时数。如果您坚持使用 int 来解决问题,另一种解决方案是通过模 100 运算来获得小时数:firstTime % 100

您提到了以 8 为基数,也称为八进制数。您显示的代码中没有任何内容会导致使用基数 8。当然,如果你使用像new TimeInterval(0700, 1400) 这样的类,那么Java 会将0700 设为base 8,所以448,你是对的。在这种情况下,您获得的小时数将为 14 - 44 = -30。再次传递一个字符串将解决它。

深入挖掘并找到一个好的解决方案

我想进一步建议:

  • 当时间为 1059 和 1202 时,它们之间有 1 小时 3 分钟。在这种情况下,您不希望小时数为 1 而不是 2?
  • 使用 java.time 的 LocalTime 类(现代 Java 日期和时间 API)作为您一天中的时间。当您在某些界面中使用军事时间时,请将其保留在界面中,无论是 Stringint 形式或两者兼而有之。在构建 TimeInterval 实例时进行适当的转换。

所以你的班级可能变成:

public class TimeInterval{
    private static final DateTimeFormatter FORMATTER_FOR_MILITARY_HOURS
            = DateTimeFormatter.ofPattern("HHmm");
    
    private LocalTime firstTime;
    private LocalTime secondTime;

    /** Main constructor */
    public TimeInterval(LocalTime firstTime, LocalTime secondTime){
        if (firstTime.isAfter(secondTime)) {
            // Switch around
            this.firstTime = secondTime;
            this.secondTime = firstTime;
        } else {
            this.firstTime = firstTime;
            this.secondTime = secondTime;
        }
    }

    /** Convenience constructor accepting military hours */
    public TimeInterval(String first, String last) {
        this(LocalTime.parse(first, FORMATTER_FOR_MILITARY_HOURS),
                LocalTime.parse(last, FORMATTER_FOR_MILITARY_HOURS));
    }

    public int getHours(){
        long differenceInHours = ChronoUnit.HOURS.between(firstTime, secondTime);
        return Math.toIntExact(differenceInHours);
    }

}

这也为我们提供了免费的范围检查:LocalTime 仅处理从 00:00 到 23:59:59.999999999 的时间。所以超出这个范围的时间会抛出异常(对不起,2400无法处理)。如果字符串的格式不正确,也会发生同样的情况,例如长度不是 4 或分钟大于 59。

便捷构造函数中的this() 是对另一个构造函数的调用,该构造函数接受LocalTIme 作为参数。

ChronoUnit.between() 返回一个长整数。由于我们知道最多可以有 23 小时,我们可以安全地转换为intMath.toIntExact() 为我们做这件事。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-04
    • 1970-01-01
    • 2020-12-09
    • 1970-01-01
    • 2019-12-27
    • 2017-08-29
    • 2017-11-22
    • 1970-01-01
    相关资源
    最近更新 更多