简体   繁体   English

为什么在使用SimpleDateFormat格式化日期然后解析它时会出现ParseException?

[英]Why am I getting a ParseException when using SimpleDateFormat to format a date and then parse it?

I have been debugging some existing code for which unit tests are failing on my system, but not on colleagues' systems. 我一直在调试一些现有的代码,我的系统上的单元测试失败了,但同事的系统却没有。 The root cause is that SimpleDateFormat is throwing ParseExceptions when parsing dates that should be parseable. 根本原因是SimpleDateFormat在解析应该可解析的日期时抛出ParseExceptions。 I created a unit test that demonstrates the code that is failing on my system: 我创建了一个单元测试,演示了我的系统失败的代码:

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

import junit.framework.TestCase;

public class FormatsTest extends TestCase {

    public void testParse() throws ParseException {
        DateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss.SSS Z");
        formatter.setTimeZone(TimeZone.getDefault());
        formatter.setLenient(false);

        formatter.parse(formatter.format(new Date()));
    }
}

This test throws a ParseException on my system, but runs successfully on other systems. 此测试在我的系统上抛出ParseException,但在其他系统上成功运行。

java.text.ParseException: Unparseable date: "20100603100243.118 -0600"
    at java.text.DateFormat.parse(DateFormat.java:352)
    at FormatsTest.testParse(FormatsTest.java:16)

I have found that I can setLenient(true) and the test will succeed. 我发现我可以setLenient(true) ,测试会成功。 The setLenient(false) is what is used in the production code that this test mimics, so I don't want to change it. setLenient(false)是此测试模拟的生产代码中使用的内容,因此我不想更改它。

--- Edited after response indicating that the developer is using IBM's J9 1.5.0 Java Virtual Machine --- ---在响应后编辑,表明开发人员正在使用IBM的J9 1.5.0 Java虚拟机---

IBM's J9 JVM seems to have a few bugs and incompatibilities in the parse routine of DateFormat, which SimpleDateFormat likely inherits because it is a subclass of DateFormat. IBM的J9 JVM似乎在DateFormat的解析例程中存在一些错误和不兼容性,SimpleDateFormat可能会继承它,因为它是DateFormat的子类。 Some evidence to support that IBM's J9 isn't functioning quite the way you might expect other JVMs (like Sun's HotSpot JVM) can be seen here . 有些证据支持IBM的J9功能不如预期的那样,其他JVM(如Sun的HotSpot JVM)可以在这里看到。

Note that these bugs and incompatibilites are not even consistent within the J9 JVM, in other words, the IBM J9 formatting logic might actually generate formatted times that are not compatible with the IBM J9 parsing logic. 请注意,这些错误和不兼容性在J9 JVM中甚至不一致,换句话说,IBM J9格式化逻辑实际上可能生成与IBM J9解析逻辑不兼容的格式化时间。

It seems that people who are tied to IBM's J9 JVM tend to work around the bug in the JVM by not using DateFormat.parse(...) (or SimpleDateFormat.parse(...)). 似乎与IBM的J9 JVM绑定的人倾向于通过不使用DateFormat.parse(...)(或SimpleDateFormat.parse(...))解决JVM中的错误。 Instead they tend to use java.util.regex.Matcher to parse the fields out manually. 相反,他们倾向于使用java.util.regex.Matcher手动解析字段。

Perhaps a later release of the J9 JVM fixes the issue, perhaps not. 也许后来发布的J9 JVM修复了这个问题,也许不是。

--- Original post follows --- ---原帖如下---

Funny, the same code modified to: 有趣,相同的代码修改为:

import java.util.Date;
import java.util.TimeZone;
import java.text.SimpleDateFormat;
import java.text.DateFormat;
import java.text.ParseException;

public class FormatsTest {

 public void testParse() throws ParseException {
  DateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss.SSS Z");
  formatter.setTimeZone(TimeZone.getDefault());
  formatter.setLenient(false);
  System.out.println(formatter.format(new Date()));

  formatter.parse(formatter.format(new Date()));
 }

 public static void main(String[] args) throws Exception {
   FormatsTest test = new FormatsTest();
   test.testParse();
 }

}

runs fine on my system. 我的系统运行正常。 I would wager that it is something in your environment. 我敢打赌,这是你环境中的事情。 Either you are compiling the code on one JVM major release and running it on another (which can cause some issues as the libraries could be out of date) or the system you are running it on might be reporting the time zone information oddly. 您要么在一个JVM主要版本上编译代码并在另一个JVM主要版本上运行它(这可能会导致一些问题,因为库可能已过期),或者您运行它的系统可能会奇怪地报告时区信息。

Finally, you might want to consider if you are using a very early point release of the JVM. 最后,您可能想要考虑是否使用了JVM的早期版本。 Sometimes bugs do creep into the various versions, and they are fixed in later point releases. 有时bug会进入各种版本,并且它们会在以后的版本中修复。 Could you please modify your question to include the "java -version" information for you system? 你可以修改你的问题,为你的系统包含“java -version”信息吗?

Either way, both of these are just educated guesses. 无论哪种方式,这两者都只是受过教育的猜测。 The code should work as written. 代码应该按照书面形式工作。

That should probably be a bug in IBM's J9 VM about the SimpleDateFormat class. 这应该是IBM的J9 VM中关于SimpleDateFormat类的错误。

This post show a similar problem, and says it should be fixed on v6. 这篇文章显示了一个类似的问题,并说它应该在v6上修复。

You may find the list of changes for several releases here . 您可以在此处找到多个版本的更改列表。

I see there's a number related to DateFormat. 我看到有一个与DateFormat相关的数字。 So, you should probably raise a bug report or something with IBM for them to give you a patch. 因此,您可能应该向IBM提出错误报告或其他内容,以便为您提供补丁。

Check the LANG environment variable of your computer and of the remote computer. 检查计算机和远程计算机的LANG环境变量。

The date is parsed according to the locale, so 'Jul' works as July only if your LANG is set to english, otherwise a ParseException is raised. 根据语言环境解析日期,因此只有当LANG设置为english时,'Jul'才能用作7月,否则会引发ParseException。

You can make a quick test by running export LANG="en_US.UTF-8" and then running your program. 您可以通过运行export LANG="en_US.UTF-8"然后运行程序来进行快速测试。

You can also set the locale programmatically, by using the following method: DateFormat.getDateInstance(int, java.util.Locale) 您还可以使用以下方法以编程方式设置语言环境: DateFormat.getDateInstance(int,java.util.Locale)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM