Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用SimpleDataFormat.parse()解析日期时出现NumberFormatException_Java_Date - Fatal编程技术网

Java 使用SimpleDataFormat.parse()解析日期时出现NumberFormatException

Java 使用SimpleDataFormat.parse()解析日期时出现NumberFormatException,java,date,Java,Date,具有创建仅限时间对象的函数。(为什么需要这样做是一个很长的故事,这在本文中是不相关的,但我需要与XML世界中的一些东西进行比较,在XML世界中,时间(即仅时间)是一个有效的概念) 在Java中,可能至少有几种其他方法可以创建一个仅限时间的日期(或者更准确地说,其中日期部分是1970-01-01),但我的问题并不是关于这个 我的问题是,这段代码在生产环境中运行了很长一段时间后,开始随机抛出NumberFormatExceptiononline#8。从技术上说,这是不可能的,对吧 下面是从上述代码中

具有创建仅限时间对象的函数。(为什么需要这样做是一个很长的故事,这在本文中是不相关的,但我需要与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);