22

我正在从 Active Directory 中获取日期值 (createWhen),并将其转换为 Java 日期,以获取在两个日期之间创建的帐户列表。一切正常,除了一种方法:我从 AD 日期到 Java 日期的方法。该方法如下所示:

private Date getParsedDate(String givenString) {
    System.out.println("Value from AD is: " + givenString);
    Date parsedDate = null;
    String formattedString = this.formatDateString(givenString);
    System.out.println("Formatted String is: " + formattedString);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/DD");
    try {
        parsedDate = sdf.parse(formattedString);
        System.out.println("Final date string is: " + parsedDate.toString());
    } catch (ParseException ex) {
        ex.printStackTrace();
    }
    return parsedDate;
}

并且,对于来自 AD 的单个任意数据:

Value from AD is: 20050912190509.0Z

Formatted String is: 2005/09/12

Final date string is: Wed Jan 12 00:00:00 EST 2005

显然,它正确地选择了日期和年份(如果我选择包括小时/分钟/秒,它也正确地包括那些),但由于某种原因,每个日期都被放置在一月份。

现在,我确信我的错误是一个非常简单的错误,但我已经重新检查了我的格式大约十次,而且我已经看不到它了。第二双眼睛能否有希望地查看我的代码并指出我哪里出错了,让月份如此严重不正确?

谢谢。

4

4 回答 4

50

将模式字符串从“yyyy/MM/DD”更改为“yyyy/MM/dd”

SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
于 2010-08-24T19:41:37.743 回答
5

确保不要使用“mm”代替“MM”或“MMM”。因为小 m 表示分钟,大写 M 表示月份。

于 2016-07-13T05:53:13.680 回答
1

TL;博士

    LocalDate parsedDate = OffsetDateTime
            .parse("20050912190509.0Z", DateTimeFormatter.ofPattern("uuuuMMddHHmmss.SX"))
            .toLocalDate();

这产生了LocalDate一个2005-09-12

java.time

我正在贡献现代答案。Suhas Phartale 的答案是正确的,并且在 7 年前编写时是一个很好的答案。现在,臭名昭著的麻烦类早已过时,而我们在现代 Java 日期和时间 APISimpleDateFormat方面有了更好的解决方案。java.time我强烈建议您使用它而不是旧的日期时间类。

细节

从您的代码看来,您在解析之前从 AD 重新格式化了您的字符串。没必要,直接解析AD中的字符串即可。我们可能直接将其解析为 a LocalDate,但我建议将其解析为 anOffsetDateTime以获取字符串的时间和偏移量;如您所见,这可以直接转换为LocalDate之后。ALocalDate是没有时间的日期,因此它似乎比旧Date课程更符合您的要求。

字符串采用 UTC 格式(Z最后用 表示)。以上为您提供了字符串中的日期,即 UTC 日期。相反,如果您想要的是 UTC 时间 9 月 12 日 19:05 时所在时区的日期:

    LocalDate parsedDate = OffsetDateTime.parse(givenString, adDateTimeFormatter)
            .atZoneSameInstant(ZoneId.of("America/Coral_Harbour"))
            .toLocalDate();

我假设我们已经将格式化程序声明为静态字段:

private static final DateTimeFormatter adDateTimeFormatter
        = DateTimeFormatter.ofPattern("uuuuMMddHHmmss.SX");

在这种情况下,结果是相同的,对于其他时区则不会。请用您自己想要的时区替换 America/Coral_Harbour。要使用 JVM 的时区设置,请指定ZoneId.systemDefault(). 但是请注意,该设置可能会被程序的其他部分或在同一 JVM 中运行的其他程序更改,因此这是脆弱的。

Suhas Phartale 的回答中的观点也是有效的java.time:格式模式字符串区分大小写,我需要在dd月份中使用小写字母。

教程

java.timeOracle 教程中了解更多信息和/或在网上搜索其他资源。

于 2017-12-11T11:08:45.970 回答
0

我发布此答案是因为我是从这里重定向的,以上解决方案没有解决我的问题

对我来说,情况是,在解析了这个日期“2020-03-01T07:00:00+0530”后,我得到的结果是 1/2 [dd/MM],这是我想要的格式,但结果包含错误的月份,因为日期字符串清楚地表明月份是3 [MARCH].

所以基本上 cal.get(Calendar.DAY_OF_MONTH) 返回我 2 而不是实际的 3。

根据MONTH 部分中的文档

“公历和儒略历中的第一个月是 JANUARY,即 0;最后一个月取决于一年中的月数。”

所以我们只需要添加一个 +1 就可以得到实际月份。猜猜这种行为可能是从月份数组中返回月份的名称吗?![1月、2月等]

下面是我的实现示例(我在字符串中的日期格式是“yyyy-MM-dd'T'HH:mm:ssZ”):

Calendar cal = Calendar.getInstance();
            SimpleDateFormat sdf = new SimpleDateFormat(Constant.DATE_FORMAT_WITH_TIMEZONE,Locale.ENGLISH);
            try {               
                cal.setTime(Objects.requireNonNull(sdf.parse(forecastList.get(listPosition).fcst_valid_local)));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            String s = "%s/%d";
            String output = String.format(s,cal.get(Calendar.DAY_OF_MONTH),(cal.get(Calendar.MONTH)+1)));

希望这对某人有所帮助。

于 2020-03-01T08:11:18.040 回答