javadatetimeandroid-jodatime

How to calculate next birthday using Joda time libaray


I have two dates in format like Date of birth suppose 1995/04/09 and current date 2016/07/24 so how can I get Months and Days remaining to next birthday

public String getNextBirthdayMonths() {
     LocalDate dateOfBirth = new LocalDate(startYear, startMonth, startDay);
     LocalDate currentDate = new LocalDate();

     Period period = new Period(dateOfBirth, currentDate);
     PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
                              .appendMonths().appendSuffix(" Months ")
                              .appendDays().appendSuffix(" Days ")
                              .printZeroNever().toFormatter();

        String nextBirthday = periodFormatter.print(period);
        return "" + nextBirthday;
}

Please anyone help me Thanks in advance


Solution

  • 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?

    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.