有一个创建仅限时间的Date对象的函数.(为什么这是必需的是一个长篇故事,在这种情况下是无关紧要的,但我需要与XML世界中的一些东西进行比较,其中TIME(即仅时间)是一个有效的概念).
private static final SimpleDateFormat DF_TIMEONLY = new SimpleDateFormat("HH:mm:ss.SSSZ");
public static Date getCurrentTimeOnly() {
String onlyTimeStr = DF_TIMEONLY.format(new Date()); // line #5
Date onlyTimeDt = null;
try {
onlyTimeDt = DF_TIMEONLY.parse(onlyTimeStr); // line #8
} catch (ParseException ex) {
// can never happen (you would think!)
}
return onlyTimeDt;
}
Run Code Online (Sandbox Code Playgroud)
可能至少有几种方法可以在Java中创建一个仅限日期的日期(或者更确切地说,日期部分是1970-01-01),但我的问题实际上并非如此.
我的问题是这段代码在生产运行很长时间后开始在#8行上随机抛出NumberFormatException.从技术上讲,我会说这应该是不可能的,对吧?
以下是来自上面一段代码的随机NumberFormatExceptions的摘录:
java.lang.NumberFormatException: multiple points
java.lang.NumberFormatException: For input string: ".11331133EE22"
java.lang.NumberFormatException: For input string: "880044E.3880044"
java.lang.NumberFormatException: For input string: "880044E.3880044E3"
Run Code Online (Sandbox Code Playgroud)
首先,我希望我们能够正式认为这应该是不可能的吗?代码使用相同的format(DF_TIMEONLY)作为输出然后输入.如果你不同意它应该是不可能的,请告诉我.
我无法在独立环境中重新生成问题.当JVM运行很长时间(> 1周)时,问题似乎就出现了.我无法找到问题的模式,即夏令时/冬令时,上午/下午等.错误是零星的,这意味着一分钟它将抛出NumberFormatException,下一分钟它将运行正常.
我怀疑在JVM或者甚至在CPU中某处存在某种算术故障.上述例外情况表明涉及浮点数,但我没有看到它们来自何处.据我所知,Java的Date对象是一个包装器,long它包含了自纪元以来的millis数.
我猜测正在发生的事情是onlyTimeStr在第5行中创建了一个意外的字符串,所以这个问题确实存在于这里而不是第8行.
以下是完整堆栈跟踪的示例:
java.lang.NumberFormatException: For input string: "880044E.3880044E3"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1241)
at java.lang.Double.parseDouble(Double.java:540)
at java.text.DigitList.getDouble(DigitList.java:168)
at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2086)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
at java.text.DateFormat.parse(DateFormat.java:355)
at org.mannmann.zip.Tanker.getCurrentTimeOnly(Tanker.java:746)
Run Code Online (Sandbox Code Playgroud)
环境:Java 7
Clo*_*use 43
可能的原因是SimpleDateFormat不是线程安全的事实,并且您从多个线程引用它.虽然极难证明(并且难以测试),但有证据表明情况如此:
.11331133EE22 - 注意一切都变了一倍880044E.3880044E3 - 同样在这里您可能至少有两个线程交错.将E被扔我,我想它试图处理科学记数法(1E10等),但它是对可能部分时区.
值得庆幸的是,(格式化)基本修复很简单:
private static final String FORMAT_STRING = "HH:mm:ss.SSSZ";
public static Date getCurrentTimeOnly() {
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_STRING);
String onlyTimeStr = formatter.format(new Date());
return formatter.parse(onlyTimeStr);
}
Run Code Online (Sandbox Code Playgroud)
你可以在这里做一些其他的事情,但有一些注意事项:
1 - 如果时区是UTC(或任何没有DST的时区),这是微不足道的
public static Date getCurrentTimeOnly() {
Date time = new Date();
time.setTime(time.getTime() % (24 * 60 * 60 * 1000));
return time;
}
Run Code Online (Sandbox Code Playgroud)
2 - 您将无法测试此方法,因为您无法安全地暂停时钟(您可以更改时区/区域设置).为了更好地处理Java中的日期/时间,请使用JodaTime之类的东西.请注意,LocalTime没有附加时区,但Date只返回整数小时的偏移量(并且小时内没有区域); 为了安全起见,你需要返回一个Calendar(带有完整的时区),或者只返回没有它的东西:
// This method is now more testable. Note this is only safe for non-DST zones
public static Calendar getCurrentTimeOnly() {
Calendar cal = new Calendar();
// DateTimeUtils is part of JodaTime, and is a class allowing you to pause time!
cal.setTimeInMillis(DateTimeUtils.currentTimeMillis() % (24 * 60 * 60 * 1000));
return cal;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12998 次 |
| 最近记录: |