给定用户活跃起止时间列表,按小时统计累计活跃秒数的更优实现方案
优化方案说明
基于Java 8+ 内置的java.time时间API实现,相比原有实现有几个明显优势:
- 线程安全的时间解析逻辑,避免原有
SimpleDateFormat多线程场景下的异常问题 - 无需手动拆分字符串处理时分秒,减少格式变动导致的业务故障
- 原生支持跨天、跨多天的活跃时长计算,修复原有实现跨2天以上场景的统计错误
- 逻辑分层清晰,后续调整统计维度(如按半小时/天拆分)改造成本极低
实现代码
import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; // 全局时间解析器,线程安全可复用 private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"); public void calculateHourlyActive(List<UserActiveRecord> objectList) { long[] hourlyUsageList = new long[24]; for (UserActiveRecord record : objectList) { // 直接将字符串解析为时间对象,无需手动拆分 LocalDateTime start = LocalDateTime.parse(record.getStartTime(), DATE_FORMAT); LocalDateTime end = LocalDateTime.parse(record.getEndTime(), DATE_FORMAT); if (start.isEqual(end)) continue; // 取开始时间所在小时的起始点作为遍历起点 LocalDateTime currentHour = start.truncatedTo(ChronoUnit.HOURS); while (currentHour.isBefore(end)) { // 当前统计小时的结束点 LocalDateTime currentHourEnd = currentHour.plusHours(1); // 计算活跃区间和当前小时区间的交集 LocalDateTime intervalStart = start.isAfter(currentHour) ? start : currentHour; LocalDateTime intervalEnd = end.isBefore(currentHourEnd) ? end : currentHourEnd; // 累加交集秒数到对应小时 long activeSeconds = ChronoUnit.SECONDS.between(intervalStart, intervalEnd); hourlyUsageList[currentHour.getHour()] += activeSeconds; // 跳转到下一个小时继续统计 currentHour = currentHourEnd; } } } // 业务实体示例,可替换为你实际的实体类 class UserActiveRecord { private String startTime; private String endTime; // 省略get/set方法 }
逻辑说明
核心逻辑是每次取活跃周期和当前统计小时区间的交集,直接计算交集的时长,不需要单独处理同小时、跨1小时、跨多天的分支逻辑,所有边界场景都由时间API原生处理,可读性和可维护性大幅提升。如果业务需要考虑时区,只需将
LocalDateTime替换为ZonedDateTime指定对应时区即可,无需修改其他统计逻辑。
内容的提问来源于stack exchange,提问作者Drashti Dobariya
相关产品推荐
相关产品推荐

