# “`plaintext Math.min 军事时间 vs 八进制 “`

go评论59阅读模式

Math.min Military Time vs Base 8

# 问题

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

public TimeInterval(int _first, int _second) {
if (_first < 0 || _second < 0) {
System.out.println("错误：无效的输入");
System.exit(0);
} else if (_first > 2400 || _second > 2400) {
System.out.println("错误：无效的输入");
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)));
}
}
``````

I'm making a program designed to get the elapsed time via military time and this is what I got so far:

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

public TimeInterval(int _first,int _second) {
if (_first &lt; 0 || _second &lt; 0) {
System.out.println(&quot;ERROR INVALID INPUT&quot;);
System.exit(0);
}
else if (_first &gt; 2400 || _second &gt; 2400) {
System.out.println(&quot;ERROR INVALID INPUT&quot;);
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)));
}
}
``````

The program works for the most part except when dealing with inputs of _first or _second that are from 0000 to 0700. The idea is that they are read as military time, but java reads them as base 8 integers and so when _first = 0700 and _second = 1400 I get 448 or something. Is there anyway I can ensure that when _first and _second are entered into Math.min they are read as base 10 instead of base 8.

# 答案1

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

• 当时间是1059和1202时，它们之间有1小时3分钟的间隔。在这种情况下，你难道不想小时数是1而不是2吗？
• 对于时间，使用`java.time``LocalTime`类，这是现代的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;

/** 主构造方法 */
public TimeInterval(LocalTime firstTime, LocalTime secondTime){
if (firstTime.isAfter(secondTime)) {
// 交换顺序
this.firstTime = secondTime;
this.secondTime = firstTime;
} else {
this.firstTime = firstTime;
this.secondTime = secondTime;
}
}

/** 便捷构造方法接受军用时间 */
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);
}

}
``````

`ChronoUnit.between()`返回一个long型。由于我们知道最多可能有23小时，所以我们可以安全地转换为`int``Math.toIntExact()`会为我们执行这个操作。

It seems you are assuming that military hours are always 4 digits with an appropriate number of leading zeroes, from 0000 through 2359. You can’t represent this concept of military hours in an int since an int hasn’t necessarily got 4 digits. The same number can be formatted into 6, 06, 006, 0006 or 000000006. Internally it’s just the same 32 bits. So when `firstTime` is 700 (or 0700), then `Integer.toString(firstTime).substring(0, 2))` takes the first two digits of 700 and yields 70 (not 7). So `new TimeInterval(700, 1400).getHours()` yields -56 (not 7). If `firstTime` is 9 (0009) or less, your code will probably crash with a `StringIndexOutOfBoundsException`.

A solution would be to pass your military hours in a `String` that always has length 4. Then your substring operation will always take the first 2 digits, the hours. If you insist on fighting your way through with `int`, another solution would be a modulo 100 operation to get the hours: `firstTime % 100`.

You mentioned base 8, also known as octal. There is nothing in the code you have shown that would cause base 8 to be used. Of course, if you use your class like `new TimeInterval(0700, 1400)`, then Java will take 0700 to be base 8, so 448, you are correct. In this case the hours you get will be 14 - 44 = -30. Again passing a string will solve it.

## Digging a bit deeper and finding a good solution

I would further like to suggest:

• When the times are 1059 and 1202, there are 1 hour 3 minutes between them. Don’t you want the hours to be 1 rather then 2 in this case?
• Use the `LocalTime` class of java.time, the modern Java date and time API, for your time of day. When you use military hours in some interface, keep them in the interface, no matter if in `String` or `int` form or both. Do the proper conversion when building your `TimeInterval` instance.

``````public class TimeInterval{
private static final DateTimeFormatter FORMATTER_FOR_MILITARY_HOURS
= DateTimeFormatter.ofPattern(&quot;HHmm&quot;);

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

}
``````

This also gives us a range check for free: `LocalTime` only handles time from 00:00 to 23:59:59.999999999. So passing time soutside this range will throw an exception (sorry, 2400 cannot be handled). The same will happen if the string is not in the correct format, like when the length isn’t 4 or the minutes are greater than 59.

The `this(``)` in the convenience constructor is a call to the other constructor, the one accepting `LocalTIme` as arguments.

`ChronoUnit.between()` returns a long. Since we know that there can be 23 hours at most, we can safely convert to `int`. `Math.toIntExact()` does that for us.

• 本文由 发表于 2020年10月3日 13:33:21
• 转载请务必保留本文链接：https://go.coder-hub.com/64181064.html
• java
• math
• military
• octal
• timeofday

go 111

go 54

go 59

go 64