Java SimpleDateFormat总是返回1月份的月份

时间:2010-08-24 19:29:04

标签: java active-directory simpledateformat

我正在从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

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

现在,我确定我的错误是一个非常简单的错误,但我已经重新检查了我的格式十次,而我正处于我再也看不到的地步。第二双眼睛是否可以查看我的代码,并指出我出错的地方让这个月变得非常不正确?

感谢。

4 个答案:

答案 0 :(得分:50)

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

SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");

答案 1 :(得分:5)

确保使用'mm'代替'MM'或'MMM'。小m代表分钟,大写M代表月份。

答案 2 :(得分:1)

TL; DR

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

这会产生LocalDate 2005-09-12

java.time

我正在贡献现代答案。 Suhas Phartale’s answer是正确的,并且在7年前编写时是一个很好的答案。现在,臭名昭着的SimpleDateFormat类已经过时了,我们在java.time,现代Java日期和时间API方面做得更好。我强烈建议你使用它而不是旧的日期时间类。

详细

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

字符串采用UTC格式(最后用Z表示)。上面给出了字符串中的日期,即UTC中的日期。如果你想要它在当地时区的日期,那就是9月12日19:05 UTC:

    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

教程

详细了解the Oracle tutorial中的java.time和/或在网上搜索其他资源。

答案 3 :(得分:0)

我之所以发布此答案,是因为我从here被重定向,并且上述解决方案无法解决我的问题

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

因此,基本上cal.get(Calendar.DAY_OF_MONTH)返回2而不是实际3。

并且按照“ MONTH”部分中的docs

“公历和朱利安历法中的一年的第一个月是 一月是0;最后取决于一个月中的月数 年。”

所以我们只需要添加+1,我们就会得到实际的月份。猜猜这种现象是否有可能从month数组中返回month的名称? [一月,二月等。]

以下是我的实现示例(字符串中的日期格式为“ 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)));

希望这对某些人有帮助。