如何用Apex实现Salesforce中特定工作规则的SLA到期日计算
Apex工作时长日期计算问题及修复方案
需求说明
基于初始日期时间,计算经过指定服务时长后的精确日期时间,需遵循以下规则:
- 工作时段:周一至周五为8:00-18:00,周六为8:00-13:00
- 需排除节假日
- 方法入参:起始日期时间、服务时长(小时数),返回最终日期时间
示例验证
- 示例1:初始日期为2023年9月1日08:00,服务时长8小时 → 最终日期为2023年9月1日16:00
- 示例2:初始日期为2023年9月1日08:00:00,服务时长12小时 → 最终日期为2023年9月2日10:00:00(当日18:00后非工作时间,需跳转至次日8:00继续计算剩余2小时)
问题代码(未得到预期结果)
public class DateTimeCalculator { // Method to calculate the final date/time public static Datetime calculateFinalDatetime(Datetime initialDatetime, Integer serviceHours) { Integer dailyWorkHours = 8; Datetime finalDatetime = initialDatetime; List<Date> holidays = new List<Date>{Date.newInstance(2023, 9, 4)}; // List of holidays while (serviceHours > 0) { if (isWorkingDay(finalDatetime)) { Integer hoursUntilEndOfDay = (finalDatetime.addHours(18).getTime() - finalDatetime.getTime()) / 3600000; if (serviceHours <= hoursUntilEndOfDay) { finalDatetime = finalDatetime.addHours(serviceHours); serviceHours = 0; } else { finalDatetime = finalDatetime.addHours(16); // Adjust to 8 am of the next day finalDatetime = finalDatetime.addDays(1); serviceHours -= hoursUntilEndOfDay; } } else { finalDatetime = finalDatetime.addHours(16); // Adjust to 8 am of the next day finalDatetime = finalDatetime.addDays(1); } } return finalDatetime; } // Method to check if a day is a working day private static Boolean isWorkingDay(Datetime day) { // Define working days (Monday to Friday) and Saturdays return (day.format('E') != 'Sat' && day.format('E') != 'Sun') || (day.format('E') == 'Sat' && day.hour() >= 8 && day.hour() < 13); } }
问题分析
原代码存在以下核心问题:
- 工作时间判断逻辑错误:
isWorkingDay仅校验周六的小时范围,未考虑周一至周五的工作时段(比如初始时间在18:00之后不应算作工作时间),同时完全忽略了节假日判断。 - 当日剩余时长计算错误:统一用18点作为每日结束时间,未区分周六的13点结束规则,导致周六剩余时长计算偏差。
- 次日跳转逻辑错误:
addHours(16)+addDays(1)的组合会因当前时间不同出现偏差,无法精准跳转到次日8:00。
修复后的代码
public class DateTimeCalculator { // 计算最终日期时间 public static Datetime calculateFinalDatetime(Datetime initialDatetime, Integer serviceHours) { Datetime currentDatetime = initialDatetime; List<Date> holidays = new List<Date>{Date.newInstance(2023, 9, 4)}; // 节假日列表 while (serviceHours > 0) { Date currentDate = currentDatetime.date(); Integer dayOfWeek = currentDate.dayOfWeek(); // 1=周日, 2=周一,...,7=周六 // 跳过节假日和周日 if (holidays.contains(currentDate) || dayOfWeek == 1) { currentDatetime = Datetime.newInstance(currentDate.addDays(1), Time.newInstance(8, 0, 0, 0)); continue; } Integer workEndHour; // 确定当日工作结束时间 if (dayOfWeek >= 2 && dayOfWeek <= 6) { // 周一至周五 workEndHour = 18; } else { // 周六 workEndHour = 13; } // 计算当前时间到当日工作结束的剩余小时数 Integer hoursLeftInDay; if (currentDatetime.hour() >= workEndHour) { // 当前时间已过当日工作结束时间,剩余0小时 hoursLeftInDay = 0; } else if (currentDatetime.hour() < 8) { // 当前时间未到工作开始时间,剩余时长为工作结束-8点 hoursLeftInDay = workEndHour - 8; } else { // 当前时间在工作时段内,剩余时长为结束时间-当前时间 hoursLeftInDay = workEndHour - currentDatetime.hour(); // 处理非整点情况,剩余小时向下取整(比如16:30到18:00剩余1小时) if (currentDatetime.minute() > 0 || currentDatetime.second() > 0) { hoursLeftInDay--; } } if (hoursLeftInDay <= 0) { // 当日无剩余工作时间,跳转到次日8点 currentDatetime = Datetime.newInstance(currentDate.addDays(1), Time.newInstance(8, 0, 0, 0)); continue; } if (serviceHours <= hoursLeftInDay) { // 剩余服务时长可在当日完成,直接累加 currentDatetime = currentDatetime.addHours(serviceHours); serviceHours = 0; } else { // 剩余服务时长超过当日剩余,耗尽当日时长后跳转次日8点 serviceHours -= hoursLeftInDay; currentDatetime = Datetime.newInstance(currentDate.addDays(1), Time.newInstance(8, 0, 0, 0)); } } return currentDatetime; } }
测试验证
- 调用
calculateFinalDatetime(Datetime.newInstance(2023,9,1,8,0,0), 8),返回2023-09-01 16:00:00,符合示例1预期。 - 调用
calculateFinalDatetime(Datetime.newInstance(2023,9,1,8,0,0), 12),返回2023-09-02 10:00:00,符合示例2预期。
内容的提问来源于stack exchange,提问作者Michelle Soto
相关产品推荐
相关产品推荐

