Java 使用SimpleDataFormat.parse()解析日期时出现NumberFormatException
具有创建仅限时间对象的函数。(为什么需要这样做是一个很长的故事,这在本文中是不相关的,但我需要与XML世界中的一些东西进行比较,在XML世界中,时间(即仅时间)是一个有效的概念) 在Java中,可能至少有几种其他方法可以创建一个仅限时间的日期(或者更准确地说,其中日期部分是1970-01-01),但我的问题并不是关于这个 我的问题是,这段代码在生产环境中运行了很长一段时间后,开始随机抛出NumberFormatExceptiononline#8。从技术上说,这是不可能的,对吧 下面是从上述代码中提取的随机数字格式概念:Java 使用SimpleDataFormat.parse()解析日期时出现NumberFormatException,java,date,Java,Date,具有创建仅限时间对象的函数。(为什么需要这样做是一个很长的故事,这在本文中是不相关的,但我需要与XML世界中的一些东西进行比较,在XML世界中,时间(即仅时间)是一个有效的概念) 在Java中,可能至少有几种其他方法可以创建一个仅限时间的日期(或者更准确地说,其中日期部分是1970-01-01),但我的问题并不是关于这个 我的问题是,这段代码在生产环境中运行了很长一段时间后,开始随机抛出NumberFormatExceptiononline#8。从技术上说,这是不可能的,对吧 下面是从上述代码中
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"
首先,我希望我们能同意,从形式上来说,这是不可能的?代码使用与输出和输入相同的格式(DF_TIMEONLY
)。如果你不同意这是不可能的,请告诉我
我无法在独立环境中重新生成问题。当JVM运行了很长时间(>1周)时,问题似乎就出现了。我找不到该问题的模式,即夏季时间/冬季时间、上午/下午等。该错误是偶发的,这意味着前一分钟它将抛出NumberFormatException,下一分钟它将正常运行
我怀疑JVM或者甚至CPU中的某个地方存在某种算术故障。上述例外情况表明涉及浮点数,但我看不出它们来自何方。据我所知,Java的Date对象是一个long
的包装器,它保存了自纪元以来的毫秒数
我猜发生的事情是,在第5行中创建了一个意外的字符串onlyTimeStr
,因此问题实际上在于这里,而不是第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)
环境:Java 7可能的原因是
SimpleDataFormat
不是线程安全的,并且您正在从多个线程引用它。虽然极难证明(也同样难以测试),但有证据表明情况确实如此:
.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);
}
在这里,你还可以做一些其他事情,但要注意以下几点: 1-如果时区为UTC(或任何不带DST的时区),则这是微不足道的
public static Date getCurrentTimeOnly() {
Date time = new Date();
time.setTime(time.getTime() % (24 * 60 * 60 * 1000));
return time;
}
2-测试此方法时会遇到问题,因为无法安全地暂停时钟(可以更改时区/区域设置)。为了更好地处理Java中的日期/时间,请使用以下内容。请注意,LocalTime
没有附加时区,但是Date
只返回以整数小时为单位的偏移量(并且有);为了安全起见,您需要返回日历(带完整时区),或者只返回不带日历的内容:
// 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;
}
虽然正确答案是Clockwork Muse提供的(问题的原因是SimpleDateFormat
不是线程安全的),但我只想提供另一种创建仅限时间的日期对象的方法:
public static Date getCurrentTimeOnly() {
Calendar rightNow = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
int hour = rightNow.get(Calendar.HOUR_OF_DAY);
int minute = rightNow.get(Calendar.MINUTE);
int second = rightNow.get(Calendar.SECOND);
int msecond = rightNow.get(Calendar.MILLISECOND);
long millisSinceMidnight
= (hour * 60 * 60 * 1000)
+ (minute * 60 * 1000)
+ (second * 1000)
+ (msecond);
return new Date(millisSinceMidnight);
}
此方法在形式上更为正确,即它处理。它并不像其他方法那样,假设自epoch以来的所有日子都有24*60*60*1000毫秒
但是,它不处理闰秒在当天的情况。Joda Time
仅供参考,2.3库专门为您提供了一个类,仅限时间,没有任何日期:。而且,它是线程安全的。似乎比处理麻烦的java.util.Date类要好得多
LocalTime LocalTime=newlocaltime();
转储到控制台
System.out.println( "localTime: " + localTime );
当运行时
localTime:16:26:28.065
java.time
带来全新,灵感来自Joda Time,定义如下
在java.time中,您会发现一个类似于Joda time中的类。我也有同样的问题,原因是SimpleDataFormat不是线程安全的,我只是在方法中添加了syncronized,它不会再次发生。您可以使用“Synchronized”块使它成为线程安全的。
比如:
synchronized (lastUpdatedFormat) {
date =
lastUpdatedFormat.parse(lastUpdatedFormat.format(currentDate));
}
不是线程安全的。下面的程序将在解析表示日期对象的字符串时重现NumberFormatException
公共类MaintainEqualThreadsPatallel{
静态整数并行计数=20;
公共静态void main(字符串[]args)引发异常{
ExecutorService executorPool=Executors.newFixedThreadPool(parallelCount);
int numberOfThreads=150;//线程总数=150*2=300。
List futureReturns=新建LinkedList();
for(int i=0;isynchronized (lastUpdatedFormat) {
date =
lastUpdatedFormat.parse(lastUpdatedFormat.format(currentDate));
}
java.lang.NumberFormatException: multiple points
java.lang.NumberFormatException: For input string: ""
java.lang.NumberFormatException: For input string: "186E.2"
java.lang.NumberFormatException: For input string: "186E.2186E2"
java.lang.NumberFormatException: For input string: "22200222E.222002224EE4"
java.lang.NumberFormatException: For input string: "22200222E.222002224EE44"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at java.text.DigitList.getDouble(DigitList.java:169)
at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
OffsetTime timeOnly = OffsetTime.now(ZoneId.systemDefault());
System.out.println(timeOnly);
Instant asInstant = LocalDate.of(1970, Month.JANUARY, 1)
.atTime(timeOnly)
.toInstant();
Date oldfashionedDateObject = DateTimeUtils.toDate(asInstant);
System.out.println("As java.util.Date: " + oldfashionedDateObject);