英文:
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 < 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)));
}
}
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
得分: 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
传递。然后你的子字符串操作总是会取前两位数字,也就是小时。如果你坚持要用int
,另一个解决方案是使用模除100操作来获取小时:firstTime % 100
。
你提到了八进制,也被称为八进制。在你展示的代码中没有任何东西会导致使用八进制。当然,如果你像这样使用你的类 new TimeInterval(0700, 1400)
,那么Java会将0700视为八进制,即448,你是正确的。在这种情况下,你得到的小时将会是14 - 44 = -30。再次传递一个字符串将解决这个问题。
深入挖掘并找到一个好的解决方案
我还想进一步建议:
- 当时间是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);
}
}
这也为我们提供了一个免费的范围检查:LocalTime
只处理从00:00到23:59:59.999999999的时间。因此,传递超出此范围的时间将引发异常(抱歉,无法处理2400)。如果字符串不是正确的格式,例如长度不是4或分钟大于59,则也会发生相同的情况。
在便捷构造函数中的this(
…)
是对另一个构造函数的调用,即接受LocalTime
作为参数的构造函数。
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 inString
orint
form or both. Do the proper conversion when building yourTimeInterval
instance.
So your class may become:
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);
}
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论