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

发布于 2024-09-04 02:30:05 字数 1029 浏览 6 评论 0原文

我一直在调试一些现有代码,这些代码的单元测试在我的系统上失败,但在同事的系统上却失败。根本原因是 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()));
    }
}

此测试在我的系统上引发 ParseException,但在其他系统上运行成功。

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

我发现我可以 setLenient(true) 并且测试会成功。 setLenient(false) 是此测试模拟的生产代码中使用的内容,因此我不想更改它。

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:

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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

居里长安 2024-09-11 02:30:05

--- 在回复后编辑,表明开发人员正在使用 IBM 的 J9 1.5.0 Java 虚拟机 ---

IBM 的 J9 JVM 似乎在 DateFormat 的解析例程中存在一些错误和不兼容性,SimpleDateFormat 可能继承它,因为它是一个子类的日期格式。可以看到一些证据来支持 IBM J9 的运行方式与您期望的其他 JVM(如 Sun 的 HotSpot JVM)不同:这里

请注意,这些错误和不兼容性甚至在 J9 JVM 中也不一致,换句话说,IBM J9 格式化逻辑实际上可能会生成与 IBM J9 解析逻辑不兼容的格式化时间。

似乎使用 IBM J9 JVM 的人倾向于通过不使用 DateFormat.parse(...) (或 SimpleDateFormat.parse(...))来解决 JVM 中的错误。相反,他们倾向于使用 java.util.regex.Matcher 手动解析字段。

也许 J9 JVM 的更高版本可以解决该问题,也许不能。

--- 原帖如下 ---

有趣的是,相同的代码修改为:

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

}

在我的系统上运行良好。我敢打赌,这一定是你的环境中的某种东西。您要么在一个 JVM 主要版本上编译代码,然后在另一个 JVM 主要版本上运行它(这可能会导致一些问题,因为库可能已过时),要么您运行代码的系统可能会奇怪地报告时区信息。

最后,您可能需要考虑是否使用 JVM 的早期版本。有时,错误确实会渗透到各个版本中,并在以后的版本中得到修复。您能否修改您的问题以包含您系统的“java -version”信息?

不管怎样,这两者都只是有根据的猜测。代码应该按编写的方式工作。

--- Edited after response indicating that the developer is using IBM's J9 1.5.0 Java Virtual Machine ---

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.

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.

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.

Perhaps a later release of the J9 JVM fixes the issue, perhaps not.

--- 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.

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?

Either way, both of these are just educated guesses. The code should work as written.

攀登最高峰 2024-09-11 02:30:05

这可能应该是 IBM J9 VM 中关于 SimpleDateFormat 类的错误。

这篇文章显示了类似的问题,并说应该是已在 v6 上修复。

您可以在此处找到多个版本的更改列表。

我看到有一个与 DateFormat 相关的数字。因此,您可能应该向 IBM 提交错误报告或其他内容,以便他们为您提供补丁。

That should probably be a bug in IBM's J9 VM about the SimpleDateFormat class.

This post show a similar problem, and says it should be fixed on 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.

忆离笙 2024-09-11 02:30:05

检查您的计算机和远程计算机的 LANG 环境变量。

日期是根据区域设置进行解析的,因此仅当您的 LANG 设置为英语时,“Jul”才用作 7 月,否则会引发 ParseException。

您可以通过运行 export LANG="en_US.UTF-8" 然后运行您的程序来进行快速测试。

您还可以使用以下方法以编程方式设置区域设置:
DateFormat.getDateInstance(int, java.util.Locale)

Check the LANG environment variable of your computer and of the remote computer.

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.

You can make a quick test by running export LANG="en_US.UTF-8" and then running your program.

You can also set the locale programmatically, by using the following method:
DateFormat.getDateInstance(int, java.util.Locale)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文