java.time
The Joda-Time team advises migration to the java.time classes.
Parsing
Your input value is close to standard ISO 8601 format. We can convert it by replacing the slashes with hyphens.
String input = "1995/04/09".replace ( "/" , "-" );
The java.time classes use ISO 8601 formats by default for parsing and generating strings representing date-time values. So no need to define a formatting pattern. The LocalDate
class can directly parse the input.
LocalDate
The LocalDate
class represents a date-only value without time-of-day and without time zone.
LocalDate dateOfBirth = LocalDate.parse ( input );
MonthDay
All we need for recurring annual events such as birthday is the month and the day. The java.time classes include MonthDay
for this purpose.
MonthDay monthDayOfBirth = MonthDay.from ( dateOfBirth );
Next we need the current date. Note that while a LocalDate
does not store a time zone internally, we need a time zone to determine today’s date. For any given moment the date varies around the world by time zone. For example, a few minutes after midnight is a new day in Paris while still “yesterday” in Montréal.
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
LocalDate today = LocalDate.now ( zoneId );
int year = today.getYear ();
With the current year in hand, we can create that year’s birthday by asking the MonthDay
instance.
LocalDate nextBirthday = monthDayOfBirth.atYear ( year );
Verify that determined date is indeed the next birthday. May have already passed, in which case we need to add a year.
if ( nextBirthday.isBefore ( today ) ) {
nextBirthday = nextBirthday.plusYears ( 1 );
}
Dump to console.
System.out.println ( "input: " + input + " | dateOfBirth: " + dateOfBirth + " | today: " + today + " | nextBirthday: " + nextBirthday );
input: 1995-04-09 | dateOfBirth: 1995-04-09 | today: 2016-07-24 | nextBirthday: 2017-04-09
Period
Now we move on to calculate the time to elapse until that next birthday. The Period
class represents a span of time in terms of years, months and days.
Period period = Period.between ( today , nextBirthday ).normalized ();
We can interrogate for the months part and the days part.
int months = period.getMonths();
int days = period.getDays();
Strings
As for reporting these values in a string, for data exchange and possibly for some reports to humans, I suggest using the standard ISO 8601 format for a span of time not tied to the timeline: PnYnMnDTnHnMnS
. The P
marks beginning, and T
separates the hours-minutes-seconds part (if any). So one month and six days would be P1M6D
.
The Period
and Duration
classes in java.time use this format by default in their toString
methods.
String output = period.toString();
Or create your own string.
String message = months + " Months " + days + " Days";
System.out.println ( "period: " + period.toString () + " | message: " + message );
period: P8M16D | message: 8 Months 16 Days
I wish I knew a way to use DateTimeFormatter
to automatically localize to a human language and cultural norms specified by a Locale
as we can with other java.time types. But this does not seem to be possible with Period
and Duration
objects, unfortunately.
TemporalAdjuster
It might be possible to package this code up into a class implementing TemporalAdjuster
. Then you could use it with the simple with
syntax.
LocalDate nextBirthday = dateOfBirth.with( MyTemporalAdjusters.nextRecurringMonthDay( myYearMonth ) );
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
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.