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.