Home > Back-end >  Remaining days taking one date as a reference in Java
Remaining days taking one date as a reference in Java

Time:08-02

I have a variable of type LocalDateTime which has a date stored, for example 14/03/2020. I would like to know how I can get the days remaining to be again the 14th day of the month 3; in this case (from August 1, 2022), there are 225 days. I really have no idea how to get that value.

CodePudding user response:

Create a LocalDate with the current year, but the month and date from the stored date. This gives you the anniversary date for the current year.

If that date has passed already, add a year to find the anniversary next year.

Then find the difference between today and the chosen anniversary as a count of days using LocalDate#until.

static long untilAnniversary(LocalDate date, LocalDate today) {
    LocalDate anniversary = today.withDayOfYear(date.getDayOfYear());
    if (anniversary.isBefore(today)) anniversary = anniversary.plusYears(1L);
    return today.until(anniversary, ChronoUnit.DAYS);
}

An example of this function in use.

LocalDateTime stored = LocalDateTime.of(LocalDate.of(2020, 3, 14), LocalTime.NOON);

long daysUntil = untilAnniversary(stored.toLocalDate(), LocalDate.now());

Update: It's probably better to use MonthDay, rather than the day of the year, as a temporal adjustment; this is most likely to handle leap days as one would expect. (h/t Basil Bourque)

static long untilAnniversary(LocalDate date, LocalDate today) {
    LocalDate anniversary = today.with(MonthDay.from(date));
    if (anniversary.isBefore(today)) anniversary = anniversary.plusYears(1L);
    return today.until(anniversary, ChronoUnit.DAYS);
}

CodePudding user response:

The Answer by erickson is good and proper. For fun, here are a couple of different solutions. One uses Period#isNegative to detect future or past. The other wraps this code as a convenient TemporalAdjuster.

Period#isNegative

This code uses Period#isNegative to figure out if the proposed March 14 is past or future.

MonthDay is a way to represent, well, a month and a day-of-month, without any particular year.

Be aware that determining today’s date requires a time zone. Each day starts earlier in the east than in the west. So while it may be “tomorrow” in Tokyo Japan, it can simultaneously be “yesterday” in Edmonton Canada. If you omit an explicit time zone, the JVM’s current default time zone is applied implicitly.

public static long daysUntilMarch14 ( ZoneId zoneId )
{
    LocalDate today = LocalDate.now( zoneId );

    MonthDay march14 = MonthDay.of( 3 , 14 );
    LocalDate then = today.with( march14 );

    if ( Period.between( today , then ).isNegative() ) { then = then.plusYears( 1 ); }
    return ChronoUnit.DAYS.between( today , then );
}

Example usage.

long days = daysUntilMarch14( ZoneId.of( "Africa/Tunis" ) );

See this code run live at Ideone.com.

225

You could also write a test for past or future as:

if( today.with( MonthDay.of( 3 , 14 ) ).isBefore( today ) ) { … add one year … }

TemporalAdjuster

If you want to get fancy, you could implement this code as a TemporalAdjuster. For similarity, see TemporalAdjusters.next(DayOfWeek dayOfWeek) API, and its source code.

public static TemporalAdjuster nextMarch14 ( )
{
    return ( Temporal temporal ) -> {
        MonthDay march14 = MonthDay.of( 3 , 14 );
        Temporal then = temporal.with( march14 );
        if ( ChronoUnit.DAYS.between( temporal , then ) < 0 )
        {
            then = then.plus( Period.ofYears( 1 ) );
        }
        return then;
    };
}

Usage:

LocalDate
.now( ZoneId.of( "Africa/Tunis" ) )
.with( UntilMarch14.nextMarch14() )

See this code run live at Ideone.com.

2023-03-14

Be aware that in java.time, in day-to-day work we do not make use of the more general interfaces, abstract classes, and superclasses. Those are intended for internal use only, generally. The Javadoc advises the use of the more concrete classes for regular work. But here, in creating a TemporalAdjuster, we are acting as if doing internal java.time work, so we make use of Temporal.

CodePudding user response:

    LocalDateTime localDatetime = LocalDateTime.of(2020, 03, 14, 0, 0);
    LocalDate date1 = localDatetime.toLocalDate(); //convert localDateTime to localDate 
    LocalDate date2 = date1.plusMonths(3); //add n months
    long days = ChronoUnit.DAYS.between(date1, date2); //get days in between

You can use ChronoUnit (https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html) to get the number of days in between.

  • Related