Java SimpleDateFormat 总是返回一月
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3560279/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java SimpleDateFormat always returning January for Month
提问by EricBoersma
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:
我正在从 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;
}
And, for a single piece of arbitrary data from AD:
而且,对于来自 AD 的单个任意数据:
Value from AD is: 20050912190509.0Z
Value from AD is: 20050912190509.0Z
Formatted String is: 2005/09/12
Formatted String is: 2005/09/12
Final date string is: Wed Jan 12 00:00:00 EST 2005
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 dateis being placed in January for some reason.
显然,它正确地选择了日期和年份(如果我选择包括小时/分钟/秒,它也会正确地包括这些),但是由于某种原因,每个日期都被放置在 1 月。
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.
谢谢。
回答by Suhas Phartale
Change the pattern string from "yyyy/MM/DD" to "yyyy/MM/dd"
将模式字符串从“yyyy/MM/DD”更改为“yyyy/MM/dd”
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
回答by Ridhuvarshan
Make sure you don'tuse 'mm' instead of 'MM' or 'MMM'. As small m denotes minutes and caps M denotes month.
确保不要使用“mm”代替“MM”或“MMM”。小 m 表示分钟,大写 M 表示月。
回答by Ole V.V.
TL;DR
TL; 博士
LocalDate parsedDate = OffsetDateTime
.parse("20050912190509.0Z", DateTimeFormatter.ofPattern("uuuuMMddHHmmss.SX"))
.toLocalDate();
This yields a LocalDateof 2005-09-12.
这将产生LocalDate的2005-09-12。
java.time
时间
I am contributing the modern answer. Suhas Phartale's answeris correct and was a good answer when it was written 7 years ago. Now the notoriously troublesome SimpleDateFormatclass 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.
我正在贡献现代答案。Suhas Phartale 的答案是正确的,并且在 7 年前写的时候是一个很好的答案。现在这个臭名昭著的麻烦SimpleDateFormat类已经过时了,我们java.time在现代 Java 日期和时间 API 方面有了更好的表现。我热烈建议您使用它而不是旧的日期时间类。
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 OffsetDateTimeto grab the time and offset from the string; as you can see, this can be directly converted to a LocalDateafterwards. A LocalDateis a date without time of day, so it seems to match your requirements better than the old Dateclass.
从你的代码看来,你在解析它之前从 AD 重新格式化了你的字符串。不需要,可以直接解析来自 AD 的字符串。我们可能已经将其直接解析为 a LocalDate,但我建议将其解析为 anOffsetDateTime以从字符串中获取时间和偏移量;如您所见,这可以直接转换为LocalDateafter。ALocalDate是没有时间的日期,因此它似乎比旧Date类更符合您的要求。
The string is in UTC (denoted by the Zin 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:
该字符串采用 UTC(由Z末尾表示)。以上为您提供了字符串中的日期,即 UTC 中的日期。相反,如果您想要它在本地时区的日期,当时它是 UTC 的 9 月 12 日 19:05:
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.
在这种情况下,结果是相同的,对于其他时区则不会。请将您自己所需的时区替换为 America/Coral_Harbour。要使用 JVM 的时区设置,请指定ZoneId.systemDefault(). 但是请注意,该设置可能会被程序的其他部分或在同一 JVM 中运行的其他程序更改,因此这很脆弱。
And the point from Suhas Phartale's answer is valid in java.timetoo: format pattern strings are case sensitive, and I needed to use lowercase ddfor day of month.
Suhas Phartale 的回答的观点在以下方面也是有效的java.time:格式模式字符串区分大小写,我需要在dd一个月中的某一天使用小写字母。
Tutorial
教程
Learn more about java.timein the Oracle tutorialand/or search for other resources on the net.
java.time在Oracle 教程中了解更多信息和/或在网上搜索其他资源。
回答by Manti_Core
I am posting this answer because i was redirected from hereand 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].
对我来说,情况是在解析这个日期“2020-03-01T07:00:00+0530”后,我得到的结果为 1/2 [dd/MM],这是我想要的格式,但该结果包含错误的月份,因为日期字符串清楚地表明月份是3 [MARCH].
So basically cal.get(Calendar.DAY_OF_MONTH) was returning me 2 instead of actual 3.
所以基本上 cal.get(Calendar.DAY_OF_MONTH) 返回的是 2 而不是实际的 3。
And as per docsin MONTH section
并根据MONTH 部分中的文档
"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."
“公历和儒略历中一年的第一个月是 JANUARY,它是 0;最后一个月取决于一年中的月数。”
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..]
所以我们只需要添加一个+1,我们就会得到实际的月份。猜猜这种行为是否可能从月份数组左右返回月份的名称?![一月、二月等..]
Below is a sample of my implementation (my date format in string is "yyyy-MM-dd'T'HH:mm:ssZ"):
下面是我的实现示例(我在字符串中的日期格式是“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.
希望这对某人有所帮助。

