I'm trying to create method, that calculates rental price of an movie depending on its release date. If movie is not older then 52 weeks, price per week is 5.00, if its between 52 - 156 weeks, price is 3.49 and if its more then 156 weeks, price is 1.99per week. If turning the rent time price class changes, then it should calculate price according to that. The one I created is calculating always like its not older then 52 weeks.
static Double getPrice(Movie movie, Integer weeksToRent) {
Double price = 0d;
Integer daysSinceMovieReleased = (Period.between(LocalDate.now(), movie.getReleaseDate()).getDays()*(-1));
Integer daysToChangeFee;
Integer daysToRent = weeksToRent * 7;
if (daysSinceMovieReleased > 1092) {
price = 1.99d * weeksToRent;
} else if (daysSinceMovieReleased > 364) {
daysToChangeFee = 1092 - daysSinceMovieReleased;
if (daysToChangeFee <= daysToRent) {
price = 3.49d * weeksToRent;
} else {
Integer daysWithNewFee = daysToRent - daysToChangeFee;
Integer daysWithOldFee = daysToRent - daysWithNewFee;
price = weeksToRent * (3.49d / daysToRent * daysWithOldFee 1.99d / daysToRent * daysWithNewFee);
}
} else {
daysToChangeFee = 364 - daysSinceMovieReleased;
if (daysToChangeFee >= daysToRent) {
price = 5.0d * weeksToRent;
} else {
Integer daysWithNewFee = daysToRent - daysToChangeFee;
Integer daysWithOldFee = daysToRent - daysWithNewFee;
price = weeksToRent * (5.0d / daysToRent * daysWithOldFee 3.49d / daysToRent * daysWithNewFee);
}
}
return price;
}
I converted weeks to days -> 52 weeks = 364 days | 156 weeks = 1092 days
And multiplied daysSinceMovieReleased with -1 because without it, the value was negative.
CodePudding user response:
It is recommended to use class BigDecimal
rather than Double
for monetary amounts. I don't think you need to deal with calculations involving number of days. Just use methods isBefore
and isAfter
. First get the date that is 52 weeks before today. Then get the date which is 156 weeks before today. Then see whether the movie release date is after the first date or after the second date and before the first date or before the second date.
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.Month;
public record Movie(LocalDate dateReleased) {
static BigDecimal getPrice(Movie movie, Integer weeksToRent) {
LocalDate newest = LocalDate.now().minusWeeks(52);
LocalDate middle = LocalDate.now().minusWeeks(156);
BigDecimal price;
if (movie.dateReleased().isAfter(newest)) {
price = new BigDecimal("5.00");
}
else if (movie.dateReleased().isAfter(middle)) {
price = new BigDecimal("3.49");
}
else {
price = new BigDecimal("1.99");
}
return price.multiply(BigDecimal.valueOf(weeksToRent.longValue()));
}
public static void main(String[] args) {
Movie movie = new Movie(LocalDate.of(2020, Month.JUNE, 6));
System.out.println(getPrice(movie, 2));
}
}
The output of the above code is:
6.98
since the movie release date is more than 52 weeks ago but less than 156 weeks ago which makes the price per week 3.49 and because the requested rental period is two weeks, the total price is 3.49 × 2
CodePudding user response:
Period.between()
always return an amount of time with date-based values (years, months, days).
Eg:
LocalDate today = LocalDate.now();
LocalDate releaseDate = today.minusWeeks(54);
Period period = Period.between(releaseDate, today);
System.out.println(period);
output
P1Y13D
Now if I call period.getDays()
it will give 13
as output because it returns the amount of days of this period
.I think the same thing is happening in your logic also.
Other easy ways of calculating number of days between two dates.
Using ChronoUnit
long days = ChronoUnit.DAYS.between(releaseDate, today);
Using Duration(most suitable in situations that measure machine-based time).
long days = Duration.between(releaseDate.atStartOfDay(),today.atStartOfDay()).toDays();
Output is 378
for both cases.
In your case it's preferrable to use ChronoUnit
since you are only interested in days.
This page here is very useful in explaining which is best for which scenario.
CodePudding user response:
Thank you guys! I think I got it. I combined all your answers and my own knowledge. I tested it and it works with my inputs. Here is my solution:
static String getPrice(Movie movie, Long weeksToRent) {
LocalDate newMovieClassUntil = movie.getReleaseDate().plusWeeks(52);
LocalDate regularMovieClassUntil = movie.getReleaseDate().plusWeeks(156);
Long daysTilChangeToRegularClass = ChronoUnit.DAYS.between(LocalDate.now(), newMovieClassUntil);
Long daysTilChangeToOldClass = ChronoUnit.DAYS.between(LocalDate.now(), regularMovieClassUntil);
DecimalFormat decimalFormat = new DecimalFormat("0.00");
Double price = 0D;
Long rentTimeInDays = weeksToRent*7;
if (daysTilChangeToRegularClass > 0 && (daysTilChangeToRegularClass - rentTimeInDays > 0)){
price = weeksToRent * 5.00D;
}
else if(daysTilChangeToRegularClass > 0 && (daysTilChangeToRegularClass - rentTimeInDays < 0)){
price = weeksToRent * ((5.00 / rentTimeInDays * daysTilChangeToRegularClass) (3.49 / rentTimeInDays * (rentTimeInDays - daysTilChangeToRegularClass)));
}
else if(daysTilChangeToRegularClass <= 0 && daysTilChangeToOldClass > 0 && (daysTilChangeToOldClass - rentTimeInDays > 0)){
price = weeksToRent * 3.49D;
}
else if (daysTilChangeToRegularClass <= 0 && daysTilChangeToOldClass > 0 && (daysTilChangeToOldClass - rentTimeInDays < 0)){
price = weeksToRent * ((3.49 / rentTimeInDays * daysTilChangeToOldClass) (1.99 / rentTimeInDays * (rentTimeInDays - daysTilChangeToOldClass)));
}
else {
price = 1.99D * weeksToRent;
}
return decimalFormat.format(price);
}