Java SimpleDateFormat 始终返回月份的一月

发布于 2024-09-15 19:43:06 字数 1087 浏览 8 评论 0原文

我正在努力从 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 的单条任意数据:

来自 AD 的值是:20050912190509.0Z

格式化字符串是:2005/09/12

最终日期字符串是:Wed Jan 12 00:00:00 EST 2005

显然,它正确地获取了日期和年份(如果我选择包含小时/分钟/秒,它也会正确包含这些内容),但由于某种原因每个日期都被安排在一月。

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

谢谢。

I'm working on taking a date value (createWhen) from Active Directory, and translating it into a Java date, for the purposes of getting a list of accounts created between two dates. Everything is working fine, save for one method: the method where I go from the AD Date to the Java date. The method looks like this:

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

And, for a single piece of arbitrary data from 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

Obviously, it's picking up the day and year correctly (and if I choose to include hours/minutes/seconds it includes those correctly as well), but every single date is being placed in January for some reason.

Now, I'm sure that my error is a pretty simple one, but I've rechecked my formatting about ten times, and I'm at the point where I just can't see it any more. Can a second pair of eyes hopefully look over my code and point out where I'm going wrong to get the month so grossly incorrect?

Thanks.

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

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

发布评论

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

评论(4

难忘№最初的完美 2024-09-22 19:43:06

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

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

Change the pattern string from "yyyy/MM/DD" to "yyyy/MM/dd"

SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
孤独岁月 2024-09-22 19:43:06

确保使用“mm”而不是“MM”或“MMM”。小写的 m 表示分钟,大写的 M 表示月份。

Make sure you don't use 'mm' instead of 'MM' or 'MMM'. As small m denotes minutes and caps M denotes month.

百思不得你姐 2024-09-22 19:43:06

TL;DR

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

这会产生 LocalDate2005-09-12

java.time

我正在贡献现代答案。 Suhas Phartale 的答案是正确的,并且在 7 年前写下时是一个很好的答案。现在,臭名昭著的麻烦的 SimpleDateFormat 类已经过时了,我们在现代 Java 日期和时间 API java.time 中拥有更好的东西。我强烈建议您使用它而不是旧的日期时间类。

详细信息

从您的代码看来,您在解析字符串之前从 AD 重新格式化了字符串。不需要,直接解析AD的字符串就可以了。我们可能直接将其解析为 LocalDate,但我建议将其解析为 OffsetDateTime 以从字符串中获取时间和偏移量;如您所见,之后可以直接将其转换为 LocalDateLocalDate 是没有时间的日期,因此它似乎比旧的 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 来表示月份中的某一天。

教程

Oracle 教程java.time 的更多信息> 和/或搜索网络上的其他资源。

TL;DR

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

This yields a LocalDate of 2005-09-12.

java.time

I am contributing the modern answer. Suhas Phartale’s answer is correct and was a good answer when it was written 7 years ago. Now the notoriously troublesome SimpleDateFormat class is long outdated and we have so much better in java.time, the modern Java date and time API. I warmly recommend you use this instead of the old date-time classes.

Details

It seems from your code that you reformat your string from AD before parsing it. There’s no need for that, the string from AD can be parsed directly. We might have parsed it directly into a LocalDate, but I recommend parsing it into an OffsetDateTime to grab the time and offset from the string; as you can see, this can be directly converted to a LocalDate afterwards. A LocalDate is a date without time of day, so it seems to match your requirements better than the old Date class.

The string is in UTC (denoted by the Z in the end). The above gives you the date from the string, that is the date in UTC. If instead you wanted the date it was in your local time zone when it was September 12 19:05 in UTC:

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

I assumed we have declared the formatter a static field:

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

In this case the result is the same, for other time zones it will not be. Please substitute your own desired time zone for America/Coral_Harbour. To use the JVM’s time zone setting, specify ZoneId.systemDefault(). Beware, however, that the setting may be changed by other parts of your program or other programs running in the same JVM, so this is fragile.

And the point from Suhas Phartale’s answer is valid in java.time too: format pattern strings are case sensitive, and I needed to use lowercase dd for day of month.

Tutorial

Learn more about java.time in the Oracle tutorial and/or search for other resources on the net.

岁吢 2024-09-22 19:43:06

我发布这个答案是因为我是从这里重定向的< /a> 和上述解决方案没有解决我的问题

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

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

并且根据 文档 在月份部分

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

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

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

希望这对某人有所帮助。

I am posting this answer because i was redirected from here and above solutions did not resolve my issue

For me the scenario was that after parsing this date "2020-03-01T07:00:00+0530" i was getting the result as 1/2 [dd/MM] which is the format that i wanted, but that result contained the wrong month since the date string clearly indicates the month is 3 [MARCH].

So basically cal.get(Calendar.DAY_OF_MONTH) was returning me 2 instead of actual 3.

And as per docs in MONTH section

"the first month of the year in the Gregorian and Julian calendars is
JANUARY which is 0; the last depends on the number of months in a
year."

so we just need to add a +1 and we would get the actual month. Guess this behavior is there may be to return the names of month from month array or so ?! [January,February,etc..]

Below is a sample of my implementation (my date format in string is "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)));

hope this helps some one.

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