Java 为什么 SimpleDateFormat() 返回错误的月份?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21760531/
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
Why does SimpleDateFormat() return wrong month?
提问by A Par
The following code gives the wrong information:
下面的代码给出了错误的信息:
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
public class test {
public static void main(String[] args) {
GregorianCalendar fmt = new GregorianCalendar(2000, 7, 3);
SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy");
String result = df.format(fmt.getTime());
System.out.println("fmt: " + result);
}
}
It outputs:
它输出:
fmt: 03-Aug-2000
fmt:2000 年 8 月 3 日
While I need the Month to be July, as I have set the month to 7?
虽然我需要月份是 7 月,因为我已将月份设置为 7?
采纳答案by Luiggi Mendoza
As noted by other people, there are two problems in your current code:
正如其他人所指出的,您当前的代码中有两个问题:
- Months are zero based. So, month 7 is August, not July =\
- Year doesn't start by default at 1900 but at 1970, but if you set the year by yourself you'll get as year the same number you're setting, in this case, 75 (not 1975 as expected).
- 月份是从零开始的。所以,第 7 个月是 8 月,而不是 7 月 =\
- 默认情况下,年份不是从 1900 年开始,而是从 1970 年开始,但是如果您自己设置年份,您将获得与您设置的年份相同的数字,在本例中为 75(不是预期的 1975 年)。
To solve this, you may create the GregorianCaledar
as new GregorianCaledar(1975, 6, 3)
. Or even better, stop working directly with this class and instead use the abstract class Calendar
:
要解决此问题,您可以创建GregorianCaledar
as new GregorianCaledar(1975, 6, 3)
。或者更好的是,停止直接使用此类,而是使用抽象类Calendar
:
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 1975);
calendar.set(Calendar.MONTH, Calendar.JULY);
calendar.set(Calendar.DATE, 3);
SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy");
String result = df.format(calendar.getTime());
System.out.println("fmt: " + result);
Why to use Calendar
instead of GregorianCalendar
? Because you should always work with abstract class/interface instead of class implementation.
为什么要使用Calendar
而不是GregorianCalendar
?因为您应该始终使用抽象类/接口而不是类实现。
回答by Uri Lukach
Of course,
当然,
You have instantiated the GregorianCalendar to year 75.
您已将 GregorianCalendar 实例化为 75 年。
What was your purpose?
你的目的是什么?
See the API
查看 API
http://docs.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html
http://docs.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html
Also pay attention that in GregorianCalendar the month start from 0
还要注意,在 GregorianCalendar 中,月份从 0 开始
Taken from the JavaDoc above:
取自上面的 JavaDoc:
"month - the value used to set the MONTH calendar field in the calendar. Month value is 0-based. e.g., 0 for January."
“月 - 用于在日历中设置 MONTH 日历字段的值。月值从 0 开始。例如,0 表示一月。”
回答by Sam I am says Reinstate Monica
My guess, is that you're expecting the 7th month to be July
, but the month
value is 0-based, so July would be represented by a 6
.
我的猜测是,您期望第 7 个月为July
,但该month
值是基于 0 的,因此 7 月将由6
.
month - the value used to set the MONTH calendar field in the calendar. Month value is 0-based. e.g., 0 for January.
月 - 用于在日历中设置 MONTH 日历字段的值。月份值是从 0 开始的。例如,0 表示一月。
You also probably want to enter the 4-digit date
您可能还想输入 4 位日期
You'd end up with the following
你最终会得到以下结果
GregorianCalendar fmt = new GregorianCalendar(1975, 6, 3);
Here's the documentation for GregorianCalendar
这是GregorianCalendar的文档
回答by Mureinik
In the GregorianCalendar
months are marked from 0
(which represents January), and so do the years. So if you want to represent July 3rd, 1975, you should use:
在GregorianCalendar
几个月从标记0
(表示1月),等做了多年。所以如果你想代表 1975 年 7 月 3 日,你应该使用:
GregorianCalendar fmt = new GregorianCalendar(1975, 6, 3);
回答by Basil Bourque
tl;dr
tl;博士
LocalDate.of( 2000 , 7 , 3 )
…or…
…或者…
LocalDate.of( 2000 , Month.JULY , 3 )
java.time
时间
As already noted, the troublesome old GregorianCalendar
has crazy numbering schemes with year, month, and day-of-week. Months are numbered 0-11 for January-December, so August is # 7 rather than # 8. Avoid these old legacy classes like the Plague. Instead, use the modern java.timeclasses.
如前所述,麻烦的老人GregorianCalendar
有疯狂的编号方案,包括年、月和星期几。一月至十二月的月份编号为 0-11,因此八月是#7 而不是#8。避免使用像瘟疫这样的旧遗留课程。相反,使用现代java.time类。
Te java.timeclasses use sane numbering:
Te java.time类使用合理的编号:
2014
means the year 2014. No funky math with 1900.2
means February, 1-12 for January-December.1
means Monday, 1-7 for Monday-Sunday per [ISO 8601][1] standard.
2014
表示 2014 年。 1900 年没有时髦的数学。2
指二月,即一月至十二月的 1-12 日。1
表示星期一,根据 [ISO 8601][1] 标准,星期一至星期日为 1-7。
LocalDate
LocalDate
The LocalDate
class represents a date-only value without time-of-day and without time zone.
该LocalDate
级表示没有时间一天和不同时区的日期,唯一的价值。
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris Franceis a new day while still “yesterday” in Montréal Québec.
时区对于确定日期至关重要。对于任何给定时刻,日期因地区而异。例如,在法国巴黎午夜过后几分钟是新的一天,而在魁北克蒙特利尔仍然是“昨天” 。
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
如果未指定时区,JVM 会隐式应用其当前默认时区。该默认值可能随时更改,因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。
Specify a proper time zone namein the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 3-4 letter abbreviation such as EST
or IST
as they are nottrue time zones, not standardized, and not even unique(!).
以、、 或等格式指定正确的时区名称。永远不要使用 3-4 个字母的缩写,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。continent/region
America/Montreal
Africa/Casablanca
Pacific/Auckland
EST
IST
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
If you want to use the JVM's current default time zone, ask for it and pass as an argument. If omitted, the JVM's current default is applied implicitly. Better to be explicit, as the default may be changed at any moment during runtimeby any code in any thread of any app within the JVM.
如果您想使用 JVM 的当前默认时区,请询问它并作为参数传递。如果省略,则隐式应用 JVM 的当前默认值。最好是明确的,因为JVM 中任何应用程序的任何线程中的任何代码都可能在运行时随时更改默认值。
ZoneId z = ZoneId.systemDefault() ; // Get JVM's current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
或指定日期。您可以通过数字设置月份,对于 1 月至 12 月,合理编号为 1-12。
LocalDate ld = LocalDate.of( 2000 , 7 , 3 ) ; // Years use sane direct numbering (2014 means year 2014). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month
enum objects pre-defined, one for each month of the year. Tip: Use these Month
objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
或者,更好的是使用Month
预定义的枚举对象,一年中的每个月都有一个。提示:Month
在整个代码库中使用这些对象而不仅仅是整数,以使您的代码更具自文档性、确保有效值并提供类型安全。
LocalDate ld = LocalDate.of( 2000 , Month.JULY , 3 ) ;
Generate a String in your desired format. Note the Locale
argument used to specify the human language and cultural norms to be used in localizing.
以您想要的格式生成一个字符串。请注意Locale
用于指定本地化中使用的人类语言和文化规范的参数。
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , Locale.US ) ;
String output = ld.format( f ) ;
03-Jul-2000
2000 年 7 月 3 日
About java.time
关于java.time
The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
该java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date
, Calendar
, & SimpleDateFormat
。
The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310。
Where to obtain the java.time classes?
从哪里获得 java.time 类?
- Java SE 8, Java SE 9, and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android, the ThreeTenABPproject adapts ThreeTen-Backport(mentioned above). See How to use ThreeTenABP….
- Java SE 8、Java SE 9及更高版本
- 内置。
- 具有捆绑实现的标准 Java API 的一部分。
- Java 9 添加了一些小功能和修复。
- Java SE 6和Java SE 7
- 多的java.time功能后移植到Java 6和7在ThreeTen-反向移植。
- 安卓
- 更高版本的 Android 捆绑实现 java.time 类。
- 对于早期的 Android,ThreeTenABP项目采用了ThreeTen-Backport(上面提到过)。请参阅如何使用ThreeTenABP ...。
The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
该ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如Interval
,YearWeek
,YearQuarter
,和更多。