What we get is an Instant and a "date-grid" defined by a period (which defines the interval of datapoints, e.g.: Every Month, Every 3 Months, etc.) and a start date where we started that grid.
private Instant getValidDate(Instant request, Instant start, Period period) {
if(isOnGrid(request, start, period)) {
return request;
}
else {
return getNextPriorDateOnGrid(request, start, period);
}
}
An example: Given are the following parameters:
request = Instant("2000-05-02T07:42:00.000Z") //Second May of 2000 7:42 AM
start = Instant("2000-01-01T06:00:00.000Z") //First January of 2000 6:00 AM
period = Period("3M") //Every 3 Months
isOnGrid(request, start, period); //Should return false
getNextPriorDate(request, start, period) //Should return the First April of 2000 6:00 AM
I really have no idea how to get this with reasonable performance (its a critical place in code)
How do you check whether a distant future date (given by the Instant) is exactly on this grid, and if not, what is the next past date that was on the grid?
EDIT: I forgot to mention: All times and dates are assumed to be in UTC Timezone
You cannot add Period
s to Instant
s. They have a different "scope".
An Instant
i simply represents a point in the timeline, counting the amount of millis/nanos from a specific point in time called "Epoch".
At this instant i, the time at the clock at the wall (even the date in a calendar) differs around the world. It depends on the timezone you are in.
A Period
respects different lengths of its representation among different timezones starting at differnt dates. For example: A month lasts 30 days in June but 31 days in August. And it is even more complex if daylight saving shifts occur.
An Instant
has no idea, what a "month" actually is. You can parse it from a String
and output it to it, but internally it does not represent a human understandable form of a month like 'Jan', 'Feb', ... .
This is, why you have to align an Instant
to a LocalDateTime
or ZonedDateTime
using a ZoneId
or an ZoneOffset
. Theses classes understand and can work with Period
s.
The following code converts your Instant
s to LocalDateTime
s to take into account the above comments:
private static Instant getValidDate2(Instant request, Instant start, Period period)
{
assert(!request.isBefore(start));
// multiplication of period only works with days exclusive or
// zero daypart of period
assert(period.getDays() == 0 || (period.getMonths() == 0 && period.getYears() == 0));
ZoneId utcZone = ZoneOffset.UTC;
LocalDateTime ldstart = LocalDateTime.ofInstant(start, utcZone);
LocalDateTime ldreq = LocalDateTime.ofInstant(request, utcZone);
// calculate an approximation of how many periods have to be applied to get near request
Duration simpleDuration = Duration.between(ldstart, ldstart.plus(period));
Duration durationToReq = Duration.between(ldstart, ldreq);
int factor = (int) (durationToReq.toDays() / simpleDuration.toDays()); // rough approximation
// go near to request by a multiple of period
Period jump = Period.of(period.getYears() * factor, period.getMonths() * factor, period.getDays() * factor);
LocalDateTime ldRunning = ldstart.plus(jump);
// make sure ldRunning < request
while (ldRunning.isAfter(ldreq)) {
ldRunning = ldRunning.minus(period);
}
// make sure we pass request and
// save the the last date before or equal to request on the grid
LocalDateTime ldLastbefore = ldRunning;
while (!ldRunning.isAfter(ldreq)) {
ldLastbefore = ldRunning;
ldRunning = ldRunning.plus(period);
}
return ldLastbefore.equals(ldreq) ? request : ldLastbefore.atZone(utcZone).toInstant();
}
Explanation:
To avoid a loop adding period
until it gets to request
, a rough approximation is done on how often period
must be added to start
to come to request
. A new period being a multiple of the request period
is then added and aligned to get the last value of the grid which is less or equal to request
. Depending on a comparation between the last value and request
, the according instant is returned. In fact, the check is useless besides the fact, that request == request
when it was on the grid and not only equal
.
Here you can find further informations about java time: https://docs.oracle.com/javase/tutorial/datetime/overview/index.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With