The comment by njzk points out the minor problem in your logic.
Using java.time
Also, you are using troublesome old date-time classes, now legacy, supplanted by the java.time classes. Much of java.time is back-ported to Android and Java 6 and Java 7 (see below).
LocalDate
The LocalDate
class represents a date-only value without time-of-day and without time zone.
Time zone
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 France is a new day while still “yesterday” in Montréal Québec.
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
int yearNumber = today.getYear();
int monthNumber = today.getMonthValue();
Year
You can maintain the state of your calendar using a type-safe Year
object rather than a mere integer number. Call toString
or getValue
to present the value to the user.
Year year = Year.from( today );
YearMonth
Probably makes more sense to maintain the state of your calendar with the YearMonth
class.
YearMonth ym = YearMonth.from( today );
Localizing
You can ask for a localized name of the month via the Month
enum. 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.
Retrieve the Month
object, and ask it to generate a localized String
object.
Month month = today.getMonth(); // Returns an object from enum rather than a mere number.
String output = month.getDisplayName(
TextStyle.NARROW ,
Locale.CANADA_FRENCH
);
Math
The classes can do the math for you, getting next or previous month. You can call plus…
or minus…
methods.
LocalDate sameDateNextMonth = today.plusMonths( 1 );
Or you can use the TemporalAdjuster
interface to manipulate values. Look for implementations in the TemporalAdjusters
(plural name) class. Note that java.time uses immutable objects. Rather than alter (mutate) the state of an object, a new object is generated with values based on values from the original.
LocalDate firstOfNextMonth = today.with( TemporalAdjusters.firstDayOfNextMonth() );
Note how much simpler and more readable this code is than the legacy code seen in the Question.
public class CalendarWidget {
Locale locale = Locale.getDefault() ; // Or ask the user, such as Locale.CANADA_FRENCH.
ZoneId zoneId = ZoneId.systemDefault() ; // Or ask the user for desired/expected zone such as `America/Montreal`.
YearMonth displayedYearMonth = YearMonth.from( LocalDate.now( zoneId ) ); // By default, initialize to ‘today’ in a particular time zone.
…
void moveToNextMonth() {
// Increment the year-month.
this.displayedYearMonth = this.displayedYearMonth.plusMonths( 1 );
this.updateUserInterface();
}
void moveToPreviousMonth() {
// Decrement the year-month.
this.displayedYearMonth = this.displayedYearMonth.minusMonths( 1 );
this.updateUserInterface();
}
void updateUserInterface() {
// Update UI.
String textForYearLabel = Integer.toString( this.displayedYearMonth.getYear() ) ;
String textForMonthLabel = this.displayedYearMonth.getMonth().getDisplayName(
TextStyle.SHORT ,
this.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.
Where to obtain the java.time classes?
- Java SE 8 and 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 6 and SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android