请你作为一个java高级后端开发工程师,来实现以下需求 如果订车费按时间段计费 00:00~3:00 每小时3元 3:00~9:00 每小时5元 9:00~12:00 每小时 10元 15:00~24:00 每小时 15元, 时间段可能不是全天候的,考虑中间存在时间断层的情况 用java代码算出我从 7月11日 12:00 一直停车到 7月12日 16:00 计算我一共要付多少钱 要求如下: 1、计算考虑跨夜的情况 2:跨夜也应按定义的时间段计费 3、把时间段设为动态可配置时间段 4、计费不能丢失精度 5、注释详细化
时间: 2023-08-24 07:07:34 浏览: 152
car-expense-tracker-service:车费追踪器应用后端
以下是实现上述需求的Java代码:
```java
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class CarRentalBilling {
// 定义时间段及对应的计费费率
private Map<String, BigDecimal> rateMap;
public CarRentalBilling() {
rateMap = new HashMap<>();
rateMap.put("00:00~03:00", new BigDecimal("3"));
rateMap.put("03:00~09:00", new BigDecimal("5"));
rateMap.put("09:00~12:00", new BigDecimal("10"));
rateMap.put("15:00~24:00", new BigDecimal("15"));
}
/**
* 计算停车费用
*
* @param startTime 开始时间,格式为"yyyy-MM-dd HH:mm"
* @param endTime 结束时间,格式为"yyyy-MM-dd HH:mm"
* @return 停车费用
*/
public BigDecimal calculateFee(String startTime, String endTime) throws ParseException {
// 将时间字符串转换为Date类型
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Date start = sdf.parse(startTime);
Date end = sdf.parse(endTime);
// 按天分割时间段
List<Date[]> timeSegments = splitTimeSegment(start, end);
// 计算每个时间段的费用
BigDecimal totalFee = BigDecimal.ZERO;
for (Date[] segment : timeSegments) {
totalFee = totalFee.add(calculateSegmentFee(segment[0], segment[1]));
}
return totalFee;
}
/**
* 分割时间段,考虑跨天的情况
*
* @param start 开始时间
* @param end 结束时间
* @return 时间段列表
*/
private List<Date[]> splitTimeSegment(Date start, Date end) {
List<Date[]> timeSegments = new ArrayList<>();
// 如果结束时间早于开始时间,表示跨天
if (end.before(start)) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(end);
calendar.add(Calendar.DATE, 1); // 结束时间加一天
end = calendar.getTime();
}
// 分割时间段
Calendar calendar = Calendar.getInstance();
calendar.setTime(start);
while (calendar.getTime().before(end)) {
Date segmentStart = calendar.getTime();
calendar.add(Calendar.HOUR_OF_DAY, 1);
Date segmentEnd = calendar.getTime();
timeSegments.add(new Date[]{segmentStart, segmentEnd});
}
return timeSegments;
}
/**
* 计算每个时间段的费用
*
* @param start 时间段开始时间
* @param end 时间段结束时间
* @return 时间段费用
*/
private BigDecimal calculateSegmentFee(Date start, Date end) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
String startStr = sdf.format(start);
String endStr = sdf.format(end);
BigDecimal fee = BigDecimal.ZERO;
for (Map.Entry<String, BigDecimal> entry : rateMap.entrySet()) {
String[] timeRange = entry.getKey().split("~");
String startRange = timeRange[0];
String endRange = timeRange[1];
// 判断时间段是否在指定的范围内
if (isInRange(startStr, endStr, startRange, endRange)) {
BigDecimal rate = entry.getValue();
long hours = getHourDifference(start, end);
fee = rate.multiply(BigDecimal.valueOf(hours));
break;
}
}
return fee;
}
/**
* 判断时间段是否在指定的范围内
*
* @param start 时间段开始时间
* @param end 时间段结束时间
* @param startRange 指定范围的开始时间
* @param endRange 指定范围的结束时间
* @return 是否在指定范围内
*/
private boolean isInRange(String start, String end, String startRange, String endRange) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
try {
Date startTime = sdf.parse(start);
Date endTime = sdf.parse(end);
Date startRangeTime = sdf.parse(startRange);
Date endRangeTime = sdf.parse(endRange);
return (startTime.equals(startRangeTime) || startTime.after(startRangeTime))
&& (endTime.equals(endRangeTime) || endTime.before(endRangeTime));
} catch (ParseException e) {
e.printStackTrace();
}
return false;
}
/**
* 计算两个时间点之间的小时差
*
* @param start 开始时间
* @param end 结束时间
* @return 小时差
*/
private long getHourDifference(Date start, Date end) {
long diff = end.getTime() - start.getTime();
return diff / (60 * 60 * 1000);
}
public static void main(String[] args) throws ParseException {
CarRentalBilling carRentalBilling = new CarRentalBilling();
BigDecimal fee = carRentalBilling.calculateFee("2022-07-11 12:00", "2022-07-12 16:00");
System.out.println("停车费用:" + fee + "元");
}
}
```
这段代码实现了按时间段计费的需求,考虑了跨夜和时间段断层的情况。具体实现步骤如下:
1. 首先定义了时间段及对应的计费费率,使用`rateMap`保存。
2. `calculateFee`方法用于计算停车费用,接收开始时间和结束时间,并返回停车费用。在方法中,首先将时间字符串转换为`Date`类型。
3. `splitTimeSegment`方法用于分割时间段,考虑跨天的情况。如果结束时间早于开始时间,表示跨天,需要将结束时间加一天。然后,使用循环和`Calendar`类将时间段按每小时分割,并保存到`timeSegments`列表中。
4. `calculateSegmentFee`方法用于计算每个时间段的费用。根据时间段的开始时间和结束时间,遍历`rateMap`中的每个时间段,判断时间段是否在指定的范围内。如果是,则根据计费费率和小时差计算费用。
5. `isInRange`方法用于判断时间段是否在指定的范围内。首先将时间字符串转换为`Date`类型,然后比较开始时间和结束时间是否在指定范围内。
6. `getHourDifference`方法用于计算两个时间点之间的小时差。
7. 在`main`方法中,创建`CarRentalBilling`对象,并调用`calculateFee`方法计算停车费用,最后输出结果。
请注意,以上代码仅供参考,具体实现可能需要根据实际需求进行调整。
阅读全文