使用SimpleDateFormat.parse()解析日期时出现NumberFormatException [英] NumberFormatException while parsing date with SimpleDateFormat.parse()

查看:246
本文介绍了使用SimpleDateFormat.parse()解析日期时出现NumberFormatException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具有创建仅时间日期的函数对象。 (为什么要这样做是一个很长的故事,在这种情况下是无关紧要的,但我需要与XML世界中的一些东西进行比较,其中TIME(即仅时间)是一个有效的概念)。

Have a function that creates a time-only Date object. (why this is required is a long story which is irrelevant in this context but I need to compare to some stuff in XML world where TIME (i.e. time-only) is a valid concept).

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

可能还有至少两种其他方式可以创建仅时间日期在Java中(或更确切地说,日期部分是1970-01-01),但我的问题并不是这个问题。

There are probably at least a couple other ways to create a time-only Date in Java (or more precisely one where the date part is 1970-01-01) but my question is really not about that.

我的问题是这段代码在生产中运行了很长时间后,开始在第8行随机抛出 NumberFormatException 。从技术上讲,我应该说这是不可能的,对吧?

My question is that this piece of code starts randomly throwing NumberFormatException on line #8 after having run in production for long time. Technically I would say that this should be impossible, right ?

这里是上面代码的随机NumberFormatExceptions的摘录:

Here's an extract of random NumberFormatExceptions that come from above piece of code:

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 )作为输出然后输入。让我知道,如果您不同意这应该是不可能的。

First of all I hope we can agree that formally this should be impossible? The code uses the same format (DF_TIMEONLY) as output and then input. Let me know if you disagree that it should be impossible.

我无法在独立环境中重现该问题。当JVM运行了很长时间(> 1周)时,似乎出现了问题。我找不到问题的模式,例如夏令时/冬令时,AM / PM等。该错误是偶发性的,这意味着一分钟它将抛出NumberFormatException,而下一分钟它将运行良好。

I haven't been able to re-produce the problem in a standalone environment. The problem seems to come when the JVM has run for a long time (>1 week). I cannot find a pattern to the problem, i.e. summer time / winter time, AM/PM, etc. The error is sporadic, meaning that one minute it will throw NumberFormatException and the next minute it will run fine.

我怀疑在JVM甚至CPU中都存在某种算术故障。上述例外情况表明其中涉及浮点数,但我看不到它们的来源。据我所知,Java的Date对象是一个 long 的包装器,该包装器保存自该时期以来的毫秒数。

I suspect that there's some kind of arithmetic malfunction somewhere in either the JVM or perhaps even in the CPU. The above exceptions suggests that there's floating point numbers involved but I fail to see where they would come from. As far as I know Java's Date object is a wrapper around a long which holds the number of millis since the epoch.

我猜正在发生的是在第5行中创建了一个意外的字符串 onlyTimeStr ,所以问题出在这里而不是在第8行。

I'm guessing what is happening is that there's an unexpected string onlyTimeStr created in line #5 so the problem really lies here rather than in line #8.

以下是完整堆栈跟踪的示例:

Here's an example of a full stacktrace:

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

推荐答案

可能的原因是 SimpleDateFormat 不是线程安全的,因此您从多个引用它线程。虽然极其难以证明(并且很难测试),但有一些证据是这种情况:

The likely cause is the fact that SimpleDateFormat isn't threadsafe, and you're referencing it from multiple threads. While extremely difficult to prove (and about as hard to test for), there is some evidence this is the case:


  1. .11331133EE22 -请注意如何将所有内容加倍

  2. 880044E.3880044E3 -同样在这里

  1. .11331133EE22 - notice how everything is doubled
  2. 880044E.3880044E3 - same here

您可能至少有两个线程交织。 E 真让我失望,我认为它正在尝试处理科学计数法(例如1E10等),但这可能属于时区

You probably have at least two threads interleaving. The E was throwing me, I was thinking it was attempting to deal with scientific notation (1E10, etc), but it's likely part of the time zone.

很高兴,(格式化)基本修复很简单:

Thankfully, the (formatting) basic fix is simple:

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






还有其他两个您也可以在这里做一些事情,但要注意以下几点:


There's a couple of other things you could be doing here, too, with a few caveats:

1-如果时区是UTC(或任何没有DST的时区),那么这很简单

1 - If the timezone is UTC (or any without DST), this is trivial

public static Date getCurrentTimeOnly() {

    Date time = new Date();

    time.setTime(time.getTime() % (24 * 60 * 60 * 1000));

    return time;
}

2-您将很难测试此方法,因为您可以不能安全地暂停时钟(您可以更改时区/语言环境)。为了更好地处理Java中的日期/时间,请使用 JodaTime 之类的东西。请注意, LocalTime 没有附加时区,但是 Date 仅返回整数小时内的偏移量(还有时区不在每小时上));为了安全起见,您需要返回日历(具有完整的时区),或者只返回没有日历的内容:

2 - You're going to have trouble testing this method, because you can't safely pause the clock (you can change the timezone/locale). For a better time dealing with date/time in Java, use something like JodaTime. Note that LocalTime doesn't have a timezone attached, but Date only returns an offset in integer hours (and there are zones not on the hour); for safety, you need to either return a Calendar (with the full timezone), or just return something without it:

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

这篇关于使用SimpleDateFormat.parse()解析日期时出现NumberFormatException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆