您似乎假设军事时间始终是 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
.
一种解决方案是将您的军事时间传递给String
始终长度为 4 的 a。然后您的子字符串操作将始终采用前 2 位数字,即小时数。如果您坚持使用int
,另一种解决方案是模 100 运算来获得小时数:firstTime % 100
.
您提到了以 8 为基数,也称为八进制数。您显示的代码中没有任何内容会导致使用基数 8。当然,如果你使用你的类 like new TimeInterval(0700, 1400)
,那么 Java 将把 0700 作为基数 8,所以 448,你是对的。在这种情况下,您获得的小时数将为 14 - 44 = -30。再次传递一个字符串将解决它。
深入挖掘并找到一个好的解决方案
我还想建议:
- 当时间是 1059 和 1202 时,它们之间有 1 小时 3 分钟。在这种情况下,您不希望小时数为 1 而不是 2 吗?
- 使用
LocalTime
java.time 类(现代 Java 日期和时间 API)作为您一天中的时间。当您在某个界面中使用军用时间时,请将其保留在界面中,无论是在String
还是int
形式或两者兼而有之。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(
...<code>) 是对另一个构造函数的调用,该构造函数接受LocalTIme
作为参数。
ChronoUnit.between()
返回一个长。由于我们知道最多可以有 23 小时,因此我们可以安全地转换为int
. Math.toIntExact()
为我们这样做。