如何不区分AM/PM检查时间段是否重叠(含±30分钟误差)
Got it, let's break down how to solve this problem. The key here is to eliminate AM/PM ambiguity entirely by mapping all times to a 12-hour cycle (0–719 minutes), then handle interval overlaps—including edge cases where intervals wrap around the 12-hour mark—while accounting for your ±30 minute tolerance.
Step 1: Normalize All Times to 12-Hour Cycle Minutes
First, convert every 24-hour time to its equivalent 12-hour cycle minute value. This removes AM/PM distinctions by taking the hour modulo 12, then calculating total minutes from the start of the 12-hour cycle:
import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; public class TimeNormalizer { // Convert 24-hour time string (e.g., "13:45") to 12-hour cycle minutes public static int convert24hTo12hMinutes(String timeStr) { LocalTime time = LocalTime.parse(timeStr, DateTimeFormatter.ofPattern("HH:mm")); int twelveHour = time.getHour() % 12; return twelveHour * 60 + time.getMinute(); } }
For example:
01:00→60minutes (1:00 in 12-hour)13:45→1*60 + 45 = 105minutes (1:45 in 12-hour)23:00→11*60 = 660minutes (11:00 in 12-hour)
Step 2: Define a 12-Hour Interval Class
Create a class to represent 12-hour intervals, including logic to handle intervals that wrap around the 12-hour mark (e.g., 11:00 PM → 1:00 AM becomes 660–60 minutes):
class TwelveHourInterval { private final int startMinutes; // 0–719 private final int endMinutes; // 0–719 public TwelveHourInterval(int start, int end) { this.startMinutes = start % 720; this.endMinutes = end % 720; } // Check if the interval wraps around the 12-hour mark (e.g., 660–60) public boolean wrapsAroundTwelve() { return startMinutes > endMinutes; } // Expand the interval by ±30 minutes and split if it wraps around public List<int[]> getExtendedIntervals(int tolerance) { List<int[]> intervals = new ArrayList<>(); int extendedStart = (startMinutes - tolerance + 720) % 720; // Avoid negative values int extendedEnd = (endMinutes + tolerance) % 720; if (!wrapsAroundTwelve() && extendedStart <= extendedEnd) { intervals.add(new int[]{extendedStart, extendedEnd}); } else { // Split into two non-wrapping intervals intervals.add(new int[]{extendedStart, 720}); intervals.add(new int[]{0, extendedEnd}); } return intervals; } }
Step 3: Overlap Check Logic
Write a utility to check if two extended intervals overlap. We need to compare all split intervals (for wrapping cases) to ensure we don't miss any overlaps:
public class OverlapChecker { private static final int TOLERANCE = 30; // ±30 minutes public static boolean hasOverlap(TwelveHourInterval interval1, TwelveHourInterval interval2) { List<int[]> extended1 = interval1.getExtendedIntervals(TOLERANCE); List<int[]> extended2 = interval2.getExtendedIntervals(TOLERANCE); // Check all combinations of extended intervals for overlap for (int[] int1 : extended1) { for (int[] int2 : extended2) { if (isNonWrappingOverlap(int1[0], int1[1], int2[0], int2[1])) { return true; } } } return false; } // Check overlap between two non-wrapping intervals (start <= end) private static boolean isNonWrappingOverlap(int s1, int e1, int s2, int e2) { return s1 < e2 && s2 < e1; } }
Step 4: Test with Your Example
Let's verify your use case:
public class Main { public static void main(String[] args) { // 1:00–3:00 (24h) → 60–180 minutes (12h) TwelveHourInterval interval1 = new TwelveHourInterval( TimeNormalizer.convert24hTo12hMinutes("01:00"), TimeNormalizer.convert24hTo12hMinutes("03:00") ); // 13:45–14:45 (24h) → 105–165 minutes (12h) TwelveHourInterval interval2 = new TwelveHourInterval( TimeNormalizer.convert24hTo12hMinutes("13:45"), TimeNormalizer.convert24hTo12hMinutes("14:45") ); // 3:15–4:00 (24h) → 195–240 minutes (12h) TwelveHourInterval interval3 = new TwelveHourInterval( TimeNormalizer.convert24hTo12hMinutes("03:15"), TimeNormalizer.convert24hTo12hMinutes("04:00") ); System.out.println(OverlapChecker.hasOverlap(interval1, interval2)); // true (overlaps directly) System.out.println(OverlapChecker.hasOverlap(interval1, interval3)); // true (within 30min tolerance) } }
Key Notes:
- AM/PM Agnostic: By mapping all times to a 12-hour cycle, we don't care if a time is AM or PM—we only look at the 12-hour window.
- Tolerance Handling: Expanding each interval by 30 minutes in both directions ensures that near-miss intervals (like 3:00 and 3:15) are counted as overlapping.
- Wrapping Intervals: Splitting intervals that wrap around the 12-hour mark lets us use simple non-wrapping overlap logic for all comparisons.
内容的提问来源于stack exchange,提问作者user2511882

