将字符串解析为 java.util.Date

parsing String into java.util.Date

我试图将输入日期字符串“2018-09-31”转换为 date.I 期望它是“2018-09-30”或至少是“2018-09-30T00:00” :00Z”。但令人惊讶的是,它竟然是不同的东西。有人可以解释为什么会这样吗?以及如何使其仅匹配输入日期?

import org.apache.commons.lang3.time.FastDateFormat;

private static final FastDateFormat dateOnlyFormat = FastDateFormat.getInstance("yyyy-MM-dd");

@Test
public void getSQLDateWithOnlyDate() {
    java.util.Date date = null;
    try {
        String dateString = "2018-09-31";
        date = dateOnlyFormat.parse(dateString);
        System.out.println("input date : " + dateString);
        System.out.println("date.toInstant() : " + date.toInstant());
        System.out.println("date.toString() : " + date.toString());
    } catch (ParseException e) {
        e.printStackTrace();
    }

}

输出

input date : 2018-09-31
date.toInstant() : 2018-09-30T14:00:00Z
date.toString() : Mon Oct 01 00:00:00 AEST 2018

出了什么问题?

OH GOD SPIDERS 已经在评论中解释了其中的一些内容。 9月有30天。您的格式化程序推断:9 月 31 日是指 9 月 30 日之后的一天,即 10 月 1 日。

但是一天中的时间,14:00:00?这是一个时区问题。如果没有另行通知,您的格式化程序会使用 JVM 的时区设置。例如,这可能是 Australia/Sydney,至少您的 Date 将其呈现为 AEST,我认为这是澳大利亚东部标准时间。因此,您的字符串被解析为 10 月 1 日的 00:00:00,与 UTC 的偏移量 +10:00。这与世界标准时间 9 月 30 日 14:00:00 相同。由于 Instant.toString() 在 UTC 中呈现时间点(由 Z 后缀表示),因此您得到 2018-09-30T14:00:00Z.

正在修复

当他们试图在你的程序上耍花样时,我建议你真的要反对。我知道您只想要约会,而不是一天中的某个时间。

    String dateString = "2018-09-31";

    try {
        LocalDate.parse(dateString);
    } catch (DateTimeParseException dtpe) {
        System.out.println(dtpe);
    }

这会打印:

java.time.format.DateTimeParseException: Text '2018-09-31' could not be parsed: Invalid date 'SEPTEMBER 31'

如果您确实想要观察到的外推行为:

    DateTimeFormatter dateFormatter = DateTimeFormatter.ISO_LOCAL_DATE
            .withResolverStyle(ResolverStyle.LENIENT);
    System.out.println(LocalDate.parse(dateString, dateFormatter));

2018-10-01

你说你已经预料到 2018-09-30,但我知道没有直接的方法可以给你那个。我的第一个建议是你再考虑一下,问问你是否真的需要这个。

在我的代码中,我使用 java.time,现代 Java 日期和时间 API。我推荐它。 LocalDate 是没有时间的日期。在我看来,这既符合您的要求,又从一开始就防止了您的时区问题。

您的方法名称 getSQLDateWithOnlyDate 可能暗示您打算将日期与 SQL 数据库一起使用? LocalDate(以及其他 java.time 类型)的一个优点是您可以将其直接传递给 PreparedStatementsetObject 方法,前提是您至少使用 Java 8 且至少 JDBC 4.2。您的 JPA 实现也应该乐于接受 LocalDate 对象。

Link: Oracle tutorial: Date Time 解释如何使用 java.time.