JavaFX应用中如何判断工作时长是否属于白天/夜间时段
嘿,咱们一步步来解决这个问题。你已经拿到了工作的开始/结束时间,也算出了总时长,现在需要把它拆分成白天(6:00-22:00)和夜间时段,尤其是像凌晨3点到晚上11点这种跨时段的复杂情况对吧?我给你整理了一套可行的方案:
核心思路
不管工作时段跨不跨天,我们都可以把整个时间段拆成三部分处理:
- 第一天的剩余时段(从开始时间到当天结束)
- 中间完整的整天(如果有的话)
- 最后一天的起始时段(从当天开始到结束时间)
对于每个部分,单独计算其中属于白天的时长,最后加起来就是总白天时长,总时长减去白天时长就是夜间时长。
代码实现(兼容你现有逻辑)
我基于你给出的代码片段,补充了白天/夜间时长的计算逻辑,还处理了跨天的场景:
import java.text.SimpleDateFormat; import java.util.Date; import java.util.Calendar; public class WorkTimeHandler { // 定义白天时段的边界:6:00到22:00 private static final int DAY_START = 6; private static final int DAY_END = 22; // 常量:1小时、1天的毫秒数 private static final long HOUR_MILLIS = 3600000L; private static final long DAY_MILLIS = 86400000L; public void CalculNbreJourTravaille() { SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm"); try { // 这里替换成你从JavaFX控件获取的开始/结束时间 Date startTime = format.parse("03/10/2024 03:00"); Date endTime = format.parse("03/10/2024 23:00"); long totalWorkMillis = endTime.getTime() - startTime.getTime(); if (totalWorkMillis <= 0) { System.out.println("结束时间不能早于开始时间,请检查输入!"); return; } // 计算白天和夜间时长 long dayWorkMillis = calculateDayTimeDuration(startTime, endTime); long nightWorkMillis = totalWorkMillis - dayWorkMillis; // 转换为更易读的小时格式 double dayHours = dayWorkMillis / (double)HOUR_MILLIS; double nightHours = nightWorkMillis / (double)HOUR_MILLIS; // 这里可以把结果绑定到JavaFX的UI控件上,比如Label // dayTimeLabel.setText(String.format("白天时长:%.2f小时", dayHours)); // nightTimeLabel.setText(String.format("夜间时长:%.2f小时", nightHours)); System.out.printf("统计结果:白天%.2f小时,夜间%.2f小时%n", dayHours, nightHours); } catch (Exception e) { e.printStackTrace(); } } // 计算两个时间之间的白天总时长(毫秒) private long calculateDayTimeDuration(Date start, Date end) { Calendar startCal = Calendar.getInstance(); startCal.setTime(start); Calendar endCal = Calendar.getInstance(); endCal.setTime(end); long totalDayMillis = 0; // 情况1:开始和结束在同一天 if (isSameDay(startCal, endCal)) { return calculateSameDayDayTime(startCal, endCal); } // 情况2:跨天,先算第一天的白天时长 Calendar dayEndOfFirstDay = (Calendar) startCal.clone(); dayEndOfFirstDay.set(Calendar.HOUR_OF_DAY, DAY_END); dayEndOfFirstDay.set(Calendar.MINUTE, 0); dayEndOfFirstDay.set(Calendar.SECOND, 0); dayEndOfFirstDay.set(Calendar.MILLISECOND, 0); Calendar dayStartOfFirstDay = (Calendar) startCal.clone(); dayStartOfFirstDay.set(Calendar.HOUR_OF_DAY, DAY_START); dayStartOfFirstDay.set(Calendar.MINUTE, 0); dayStartOfFirstDay.set(Calendar.SECOND, 0); dayStartOfFirstDay.set(Calendar.MILLISECOND, 0); long firstDaySegmentStart = Math.max(start.getTime(), dayStartOfFirstDay.getTime()); long firstDaySegmentEnd = Math.min(end.getTime(), dayEndOfFirstDay.getTime()); if (firstDaySegmentStart < firstDaySegmentEnd) { totalDayMillis += firstDaySegmentEnd - firstDaySegmentStart; } // 计算中间完整的整天的白天时长(每天白天固定16小时) startCal.add(Calendar.DAY_OF_YEAR, 1); while (!isSameDay(startCal, endCal)) { totalDayMillis += (DAY_END - DAY_START) * HOUR_MILLIS; startCal.add(Calendar.DAY_OF_YEAR, 1); } // 计算最后一天的白天时长 Calendar dayStartOfLastDay = (Calendar) endCal.clone(); dayStartOfLastDay.set(Calendar.HOUR_OF_DAY, DAY_START); dayStartOfLastDay.set(Calendar.MINUTE, 0); dayStartOfLastDay.set(Calendar.SECOND, 0); dayStartOfLastDay.set(Calendar.MILLISECOND, 0); Calendar dayEndOfLastDay = (Calendar) endCal.clone(); dayEndOfLastDay.set(Calendar.HOUR_OF_DAY, DAY_END); dayEndOfLastDay.set(Calendar.MINUTE, 0); dayEndOfLastDay.set(Calendar.SECOND, 0); dayEndOfLastDay.set(Calendar.MILLISECOND, 0); long lastDaySegmentStart = Math.max(startCal.getTime(), dayStartOfLastDay.getTime()); long lastDaySegmentEnd = Math.min(end.getTime(), dayEndOfLastDay.getTime()); if (lastDaySegmentStart < lastDaySegmentEnd) { totalDayMillis += lastDaySegmentEnd - lastDaySegmentStart; } return totalDayMillis; } // 判断两个Calendar是否是同一天 private boolean isSameDay(Calendar cal1, Calendar cal2) { return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR); } // 计算同一天内的白天时长 private long calculateSameDayDayTime(Calendar start, Calendar end) { Calendar dayStart = (Calendar) start.clone(); dayStart.set(Calendar.HOUR_OF_DAY, DAY_START); dayStart.set(Calendar.MINUTE, 0); dayStart.set(Calendar.SECOND, 0); dayStart.set(Calendar.MILLISECOND, 0); Calendar dayEnd = (Calendar) start.clone(); dayEnd.set(Calendar.HOUR_OF_DAY, DAY_END); dayEnd.set(Calendar.MINUTE, 0); dayEnd.set(Calendar.SECOND, 0); dayEnd.set(Calendar.MILLISECOND, 0); // 取重叠区间的起始和结束时间 long segmentStart = Math.max(start.getTimeInMillis(), dayStart.getTimeInMillis()); long segmentEnd = Math.min(end.getTimeInMillis(), dayEnd.getTimeInMillis()); return segmentStart < segmentEnd ? segmentEnd - segmentStart : 0; } // 测试用主方法 public static void main(String[] args) { new WorkTimeHandler().CalculNbreJourTravaille(); } }
额外建议
如果你的项目使用Java 8及以上版本,强烈建议替换成java.timeAPI(比如LocalDateTime、Duration),旧的Date和Calendar不仅难用,还存在线程安全问题。用新API的话,代码会更简洁易懂,比如判断同一天可以直接用LocalDate.from(startTime).isEqual(LocalDate.from(endTime))。
另外,把计算结果集成到JavaFX界面时,直接把格式化后的字符串绑定到UI控件的textProperty()就可以了,比如:
Label dayTimeLabel = new Label(); dayTimeLabel.setText(String.format("白天时长:%.2f小时", dayHours));
内容的提问来源于stack exchange,提问作者DJIBFX
相关产品推荐
相关产品推荐

