简体   繁体   中英

Why does (MonthName.format(c.get(Calendar.MONTH))) return wrong month?

I was trying out the Time class in Java and the following outputs December even though the system time shows March:

Calendar c = Calendar.getInstance();
SimpleDateFormat MonthName = new SimpleDateFormat("MMMM");
System.out.println(MonthName.format(c.get(Calendar.MONTH)));

But using this returns March:

System.out.println(MonthName.format(c.getTime()));

I am aware that the counting of months in JAVA begins from 0 and not 1 one so it displaying February would be appropriate but March?

Because c.get(Calendar.MONTH) returns a number, and calling format(number) is the same as calling format(new Date(number)) (check here ).

In this case, c.get(Calendar.MONTH) returns 2 , because - as you said - this API uses 0-based months, so March is 2.

When you call format(2) , it's equivalent to calling format(new Date(2)) , which means a date that corresponds to "2 milliseconds after unix epoch ", which is 1970-01-01T00:00:00.002 (basically, 2 milliseconds after January 1st 1970 at midnight in UTC ).

Then, this date (Jan 1st 1970 UTC ) will be formatted by your SimpleDateFormat , which uses the JVM default timezone. So, when that date (that corresponds to Jan 1st in UTC) is converted to your JVM default timezone, gives you "December". Just print the value of new Date(2) and see what you get (spoiler: it'll be a date in December 31st 1969).


Your second attempt works because c.getTime() returns a java.util.Date , which in this case will correspond to March.

The SimpleDateFormat expects a date, not a month number

Calendar c = Calendar.getInstance();
Date d = c.getTime();
SimpleDateFormat MonthName = new SimpleDateFormat("MMMM");    
System.out.println(MonthName.format(d));

tl;dr

LocalDate.now()                  // Better to specify time zone explicitly: LocalDate.now( ZoneId.of( "Pacific/Auckland" ) )
    .getMonth                    // Get `Month` enum object appropriate to that date in that zone.
    .getDisplayName(             // Generate a `String`, the localized name of the month.
        FormatStyle.FULL ,       // Control how long or how abbreviated the text.
        Locale.CANADA_FRENCH     // Specify the human language and cultural norms to be applied in localizing.
    )

java.time

The Answer by posutes is correct.

The modern approach uses the java.time classes that supplanted the troublesome old legacy date-time classes ( Date , Calendar , SimpleDateFormat ).

ZonedDateTime replaces Calendar , representing a moment on the timeline with the wall-clock time used by people of a certain region (a time zone), with a resolution of nanoseconds.

ZonedDateTime zdt = ZonedDateTime.now() ;   // Would be better to pass explicitly the desired/expected time zone rather than implicitly rely on the JVM’s current default.

Retrieve a Month enum object for the month of this ZonedDateTime object's date.

Month month = zdt.getMonth() ;

Generate a string for the name of the month, automatically localized. To localize, specify:

  • TextStyle to determine how long or abbreviated should the string be.
  • Locale to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, separators, and such.

Ask for localized name of month.

Locale locale = Locale.US ;  // Or Locale.CANADA_FRENCH etc.
String monthName = month.getDisplayName( FormatStyle.FULL , locale ) ;

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat .

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes.

To learn more, see the Oracle Tutorial . And search Stack Overflow for many examples and explanations. Specification is JSR 310 .

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project 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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM