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

将字符串解析为java.util.Date,java,string,parsing,datetime,date-conversion,Java,String,Parsing,Datetime,Date Conversion,我试图将输入日期字符串“2018-09-31”转换为日期。我希望它是“2018-09-30”或至少是“2018-09-30T00:00:00Z”。但令人惊讶的是,结果却有所不同。有人能解释为什么会这样吗?如何使其仅与输入日期匹配 import org.apache.commons.lang3.time.FastDateFormat; private static final FastDateFormat dateOnlyFormat = FastDateFormat.getInstance("

我试图将输入日期字符串“2018-09-31”转换为日期。我希望它是“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();
    }

}

输出 出了什么问题? 哦,天哪,蜘蛛已经在评论中解释了其中的一些。九月有30天。您的格式化程序推断:9月31日是指9月30日之后的一天,即10月1日

但是一天中的时间,
14:00:00
?这是一个时区问题。如果没有告诉格式化程序,格式化程序将使用JVM的时区设置。例如,这可能是澳大利亚/悉尼,至少您的
日期
将其呈现为
AEST
,我认为这是指澳大利亚东部标准时间。因此,字符串被解析为10月1日的00:00:00,偏移量为UTC的+10:00。这与UTC 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:无法找到文本“2018-09-31” 被解析:无效日期“9月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
类型)的一个优点是,只要您至少使用java 8和JDBC 4.2,就可以将其直接传递给
PreparedStatement
setObject
方法。您的JPA实现也应该乐于接受
LocalDate
对象

链接:解释如何使用
java.time

出了什么问题? 哦,天哪,蜘蛛已经在评论中解释了其中的一些。九月有30天。您的格式化程序推断:9月31日是指9月30日之后的一天,即10月1日

但是一天中的时间,
14:00:00
?这是一个时区问题。如果没有告诉格式化程序,格式化程序将使用JVM的时区设置。例如,这可能是澳大利亚/悉尼,至少您的
日期
将其呈现为
AEST
,我认为这是指澳大利亚东部标准时间。因此,字符串被解析为10月1日的00:00:00,偏移量为UTC的+10:00。这与UTC 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:无法找到文本“2018-09-31” 被解析:无效日期“9月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
类型)的一个优点是,只要您至少使用java 8和JDBC 4.2,就可以将其直接传递给
PreparedStatement
setObject
方法。您的JPA实现也应该乐于接受
LocalDate
对象


链接:解释如何使用
java.time

为什么不看看九月份有多少天。这应该能回答你的问题;)解析日期时,溢出时的日期“滚动”,因此33.1等于2.2(31.1+1day+1day)java.util.Date已经过时。您还可以使用严格的日期解析,在这种情况下,代码将抛出异常并以错误结束,告诉您没有31.9。但无论如何它都不会变成30.9。谢谢@ohgodspeiders的快速回答。上游试图与我的客户玩把戏,我猜;)谢谢,当您将dateString解析为java.util.Date时,应该使用DateFormat(即SimpleDataFormat,以匹配所需的模式)。为了回答下一部分,您通过了2018-09-31,但是您的toInstant()方法生成2018-09-30T14:00:00Z,而不是2018-09-31T00:00:00Z,因为它涉及您的时区。根据你的时区,这个值会改变。你为什么不看看九月份有多少天。这应该能回答你的问题;)解析日期时,溢出时的日期“滚动”,因此33.1等于2.2(31.1+1day+1day)java.util.Date已经过时。您还可以使用严格的日期解析,在这种情况下,代码将抛出异常并以错误结束