I have an HTML popup menu listing various year-month combinations. Each menu item has a localized string representation such as Nov 2015
for content display, along with an attribute of a coded value such as 201511
.
For example:
<select name="selectPeriod">
<option value="201511">Nov 2015</option>
<option value="201510">Oct 2015</option>
<option value="201509">Sept 2015</option>
I generate the coded value string using java.util.Calendar.
int month = Calendar.getInstance().get(Calendar.MONTH)+1;
int year = Calendar.getInstance().get(Calendar.YEAR);
String v = String.valueOf( year ) + String.valueOf( month );
This works, but it seems weird to be using Calendar (a date plus a time-of-day) when all I really care about is year + month without a date or time-of-day.
Is there some better way in modern Java to handle a year + month?
Indeed there is a more elegant way to handle YearMonth in modern Java, with the java.time framework built into Java 8 and later.
Also your example code suffers from a couple other problems:
Getting the current moment twice, redundantly, is a bad practice. If those two lines of code happen to occur around the stroke of midnight, you will be working with two different dates and possibly two different months or even years!
Discussed below.
java.time
The old java.util.Calendar/.Date classes are notoriously troublesome and should be avoided. They have been supplanted in Java 8 and later by the java.time framework.
The new classes are inspired by the highly successful Joda-Time framework, intended as its successor, similar in concept but re-architected. Defined by JSR 310. Extended by the ThreeTen-Extra project. See the Tutorial.
YearMonth
The new classes include a class,
YearMonth
, exactly for your purpose: To represent a year+month without any date, time-of-day, or time zone.I recommend using objects of this class in your business logic, resorting to strings only where necessary such as generating that HTML.
Time Zone
While no time zone is included inside a YearMonth, note that a time zone is crucial in determining the current YearMonth. The current date, and therefore YearMonth, varies around the world at any moment. A new day dawns in the east such as Paris earlier than in the west such as Montréal where it is still “yesterday”.
If the time zone is omitted as in your example code, the JVM’s current default time zone is implicitly used. This implicit use means your results may vary for any of several reasons: Your code may move to another machine, a sysadmin may change the host machine’s default, or even worse, any code in any thread of any app running within the same JVM can change the time zone at runtime. Better to specify the desired/expected time zone (
ZoneId
in java.time).String Formats
The
toString
method by default in java.time classes use the standard ISO 8601 formats. Your format,YYYYMM
is similar to the standard formats but in this particular case (year-month) a hyphen is required to avoid ambiguity,YYYY-MM
. Most of the standard formats allow a "basic" variation omitting the hyphens, but not here.I strongly suggest making your String representations of date-time values in ISO 8601 format whenever possible.
I strongly suggest using that format in your HTML attribute. Sticking with ISO 8601 will simplify your life. Like this (note the hyphen):
But if you insist, you could build the string without the hyphen by specifying a custom formatter pattern.
Localized Strings
Let java.time do the work of localizing the display text. Notice the
Locale
passed to the DateTimeFormatter rather than relying implicitly on the JVM’s current default Locale.Date
If you need a specific date, specify a day-of-month to combine with this year and month.
From there you can get a specific moment, such as the first moment of the day. Do not assume the day starts at 00:00:00. Let java.time determine the first moment.
If you need same moment viewed in UTC, extract an
Instant
.