java 为什么在使用 SimpleDateFormat 格式化日期然后解析它时会收到 ParseException?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2967613/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why am I getting a ParseException when using SimpleDateFormat to format a date and then parse it?
提问by Greg
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. I created a unit test that demonstrates the code that is failing on my system:
我一直在调试一些现有代码,这些代码的单元测试在我的系统上失败了,但在同事的系统上却没有。根本原因是 SimpleDateFormat 在解析应该可解析的日期时抛出 ParseExceptions。我创建了一个单元测试来演示在我的系统上失败的代码:
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. The setLenient(false)is what is used in the production code that this test mimics, so I don't want to change it.
我发现我可以setLenient(true)并且测试会成功。这setLenient(false)是此测试模拟的生产代码中使用的内容,因此我不想更改它。
采纳答案by Edwin Buck
--- 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. 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 似乎在 DateFormat 的解析例程中存在一些错误和不兼容,SimpleDateFormat 可能继承了它,因为它是 DateFormat 的子类。可以在此处看到一些支持 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(...)). Instead they tend to use java.util.regex.Matcher to parse the fields out manually.
似乎绑定到 IBM 的 J9 JVM 的人倾向于通过不使用 DateFormat.parse(...)(或 SimpleDateFormat.parse(...))来解决 JVM 中的错误。相反,他们倾向于使用 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 主要版本上编译代码并在另一个版本上运行它(这可能会导致一些问题,因为库可能已过时)或者您运行它的系统可能会奇怪地报告时区信息。
Finally, you might want to consider if you are using a very early point release of the JVM. Sometimes bugs do creep into the various versions, and they are fixed in later point releases. Could you please modify your question to include the "java -version" information for you system?
最后,您可能需要考虑是否使用 JVM 的早期版本。有时错误确实会蔓延到各种版本中,并且会在以后的版本中修复。您能否修改您的问题以包含您系统的“java -version”信息?
Either way, both of these are just educated guesses. The code should work as written.
无论哪种方式,这两者都只是有根据的猜测。代码应该像编写的那样工作。
回答by OscarRyz
That should probably be a bug in IBM's J9 VM about the SimpleDateFormat class.
这可能是 IBM 的 J9 VM 中关于 SimpleDateFormat 类的错误。
This postshow 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. So, you should probably raise a bug report or something with IBM for them to give you a patch.
我看到有一个与 DateFormat 相关的数字。因此,您可能应该向 IBM 提交错误报告或其他内容,以便他们为您提供补丁。
回答by David Riccitelli
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 设置为英语时,“Jul”才作为七月工作,否则会引发 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)

