Sam正在兼职卡车司机。如果他从0200时 - 06:00开车,他可获得特别津贴。他的老板想知道这段时间所涉及的所有行程。以下是他最近4次旅行的详细信息。
旅行1:
StartDateTime:01-JAN-2017 00.15.00
EndDateTime:03-JAN-2017 01.45.00
感动:真实
旅行2:
StartDateTime:04-JAN-2017 13.00.00
EndDateTime:05-JAN-2017 13.00.00
感动:真实
旅行3:
StartDateTime:06-JAN-2017 00.00.00
EndDateTime:06-JAN-2017 05.00.00
感动:真实
旅行4:
StartDateTime:06-JAN-2017 06.01.00
EndDateTime:06-JAN-2017 23.00.00
感动:错误
我想出了我自己的实现,在java中找到这个,如果情况很少,但我有一种感觉,我正在重新发明轮子。如果日期范围触及时间范围,最好的方法是什么?
编辑:添加以下方法
public boolean isTripTouchingTimeRange(Date startDate, Date endDate, AllowanceDefinition def) {
int checkConstant = HOURS_IN_A_DAY - (def.getEndMinute() - def.getStartMinute());
// HOURS_IN_A_DAY = 1440 MINUTES (2400 HRS) ; def.getEndMinute() = 360
// MINUTES (0600 HRS) ; def.getStartMinute() = 120 MINUTES (0200 HRS)
DateTime start = new DateTime(startDate);
DateTime end = new DateTime(endDate);
if (DateUtil.subtractDates(start.toDate(), end.toDate()) > checkConstant) {
return true;
} else if (end.withTimeAtStartOfDay().isAfter(start.withTimeAtStartOfDay())
&& (end.getMinuteOfDay() > def.getStartMinute())) {
return true;
} else if (start.getMinuteOfDay() <= def.getEndMinute() && def.getStartMinute() <= end.getMinuteOfDay()) {
return true;
}
return false;
}
答案 0 :(得分:2)
此问题类似于循环值的交集。
如果您的解决方案使用了大量案例,请考虑三角函数类比here。使用余弦函数解决了日复一日包装和非平凡区间重叠的问题。
日期和时间可以转换为像
这样的角度TimeAngle = Pi * TimeHrs / 12
请注意,时间范围和旅行时间应该是&#34;标准化&#34;:
TripStartAngle = Pi * StartTripTimeHrs / 12
例如,对于06:00时间角度为Pi*6/12 = Pi/2 = 90 degree
(想象24小时钟面上的时针角度)TripEndAngle = Pi * EndTripTimeHrs / 12
。如果结束角度小于开始(由于日期更改),请添加2 * Pi
例如,对于15:00,时间角度为Pi*15/12 = 1.25 * Pi
但是对于03:00时间角度是Pi*3/12 = Pi/4 - less than starting Pi/2, so add 2*Pi, and result is 2.25*Pi
答案 1 :(得分:0)
我应该首先在代码中写出来,因为我认为这可能更简单(或者至少我熟悉)以毫秒时间戳来思考。如果我有时间,我仍然可以回去做。
在相关的说明中,我发现Interval trees是一个有趣的读物,尽管我并没有追求它。
我不相信以下是正确的,特别是我的规则&#39;关于如何选择0200/0600的日期组件。需要进行模拟测试,但是。 。
如果Sam开车20个小时或更长时间,那么他已经以某种方式触及了时间范围。 (例如Trips 1&amp; 2)
如果Sam开车的时间少于20小时,那么我们可以使用他的旅行时间来限制我们的可能性范围。
0200/0600的日期组件是根据开始日期确定的。如果startDateTime的时间组件在0000和0600之间(包括),则0200/0600共享startDateTime的日期组件,否则它是第二天。
duration = endDateTime - startDateTime
mustStartTime = 0200 - duration
mustEndTime = 0600 + duration
touched = (startDateTime >= mustStartTime && endDateTime <= mustEndTime)
旅行3
duration = 5 hours
mustStartTime = 2100 = 0200 - 5
mustEndTime = 1100 = 0600 + 5
touched = (0000 >= 2100 && 0500 <= 1100) = (true && true)
旅行4
duration = 16hr 59min
mustStartTime = 1001 = 0200 - 16 hr 59 min
mustEndTime = 2159 = 0500 + 16 hr 59 min
touched = false = (0601 >= 1001 && 2300 <= 2159) = (false && false)
旅行5
duration = 1 hour
mustStartTime = 0100 = 0200 - 1 hour
mustEndTime = 0700 = 0600 + 1 hour
touched = true = (0300 >= 0100 && 0400 <= 0700) = (true && true)
旅行6
duration = 1hr 30 min
mustStartTime = 0030 = 0200 - 1hr 30 min
mustEndTime = 0730 = 0600 + 1hr 30 min
touched = false = (0000 >= 0030 && 0130 <= 0730) = (false && true)
旅行7
duration = 1 hour
mustStartTime = 0100 = 0200 - 1 hour
mustEndTime = 0700 = 0600 + 1 hour
touched = (0500 >= 0100 && 0600 <= 0700) = (true && true)
现在使用代码&amp;测试。所有断言都是正确的!绝对感觉像车轮重塑!
public class OverlappingDateRangeUtil {
/**
* 1000 ms * 60 s * 60 m
*/
public static final long MS_IN_AN_HOUR = 1000 * 60 * 60;
public static final long MS_IN_TWO_HOURS = 2 * MS_IN_AN_HOUR;
public static final long MS_IN_SIX_HOURS = 3 * MS_IN_TWO_HOURS;
public static final long MS_IN_TWENTY_HOURS = 20 * MS_IN_AN_HOUR;
private static boolean tripLongerThanTwentyHours(long duration) {
return duration >= MS_IN_TWENTY_HOURS;
}
private static long getTruncDateFor0200And0600(Date start) {
Calendar cal = new GregorianCalendar();
cal.setTime(start);
int startHour = cal.get(Calendar.HOUR);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
boolean after0600 = startHour >=6 && start.getTime() % 60000 > 0;
if(after0600) {
cal.add(Calendar.DATE, 1);
}
return cal.getTimeInMillis();
}
public static boolean dateRangeTouches0200to0600(Date start, Date end) {
boolean toReturn = false;
long duration = end.getTime() - start.getTime();
if(tripLongerThanTwentyHours(duration)) {
toReturn = true;
}
else {
long truncTestDate = getTruncDateFor0200And0600(start);
long oh200 = truncTestDate + MS_IN_TWO_HOURS;
long oh600 = truncTestDate + MS_IN_SIX_HOURS;
long mustStart = oh200 - duration;
long mustEnd = oh600 + duration;
toReturn = start.getTime() >= mustStart && end.getTime() <= mustEnd;
}
return toReturn;
}
}
public class OverlappingDateRangeUtilTest {
private DateFormat dateTimeFormat;
@Before
public void setUp() throws Exception {
dateTimeFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
}
@Test
public void testDateRangeTouches0200to0600() throws ParseException {
Date trip1Start = dateTimeFormat.parse("01/01/2017 00:15:00");
Date trip1End = dateTimeFormat.parse("01/03/2017 01:45:00");
assertTrue(OverlappingDateRangeUtil.dateRangeTouches0200to0600(trip1Start, trip1End));
Date trip2Start = dateTimeFormat.parse("01/04/2017 13:00:00");
Date trip2End = dateTimeFormat.parse("01/05/2017 13:00:00");
assertTrue(OverlappingDateRangeUtil.dateRangeTouches0200to0600(trip2Start, trip2End));
Date trip3Start = dateTimeFormat.parse("01/06/2017 00:00:00");
Date trip3End = dateTimeFormat.parse("01/06/2017 05:00:00");
assertTrue(OverlappingDateRangeUtil.dateRangeTouches0200to0600(trip3Start, trip3End));
Date trip4Start = dateTimeFormat.parse("01/06/2017 06:01:00");
Date trip4End = dateTimeFormat.parse("01/06/2017 23:00:00");
assertFalse(OverlappingDateRangeUtil.dateRangeTouches0200to0600(trip4Start, trip4End));
Date trip5Start = dateTimeFormat.parse("01/06/2017 06:01:00");
Date trip5End = dateTimeFormat.parse("01/06/2017 06:01:00");
assertFalse(OverlappingDateRangeUtil.dateRangeTouches0200to0600(trip5Start, trip5End));
Date trip6Start = dateTimeFormat.parse("01/06/2017 04:00:00");
Date trip6End = dateTimeFormat.parse("01/06/2017 04:00:00");
assertTrue(OverlappingDateRangeUtil.dateRangeTouches0200to0600(trip6Start, trip6End));
Date trip7Start = dateTimeFormat.parse("01/06/2017 03:00:00");
Date trip7End = dateTimeFormat.parse("01/06/2017 04:00:00");
assertTrue(OverlappingDateRangeUtil.dateRangeTouches0200to0600(trip7Start, trip7End));
Date trip8Start = dateTimeFormat.parse("01/06/2017 00:00:00");
Date trip8End = dateTimeFormat.parse("01/06/2017 01:30:00");
assertFalse(OverlappingDateRangeUtil.dateRangeTouches0200to0600(trip8Start, trip8End));
}
}
答案 2 :(得分:0)
问题不完整。
在日期工作中,我们遇到异常。 Daylight Saving Time (DST)最常见的。但我们也有政治家经常重新定义时区的问题,正如过去几年Turkey(2016),Russia(2016年,2014年,2011年),Venezuela(2016年)所发生的那样。 ,2007)等地。
所以你必须决定如何处理这种异常现象。例如,在DST切换时,这一天可以是23或25小时。在美国,DST意味着不是凌晨2点或凌晨2点。请注意,DST切换发生在美国以外其他地方的其他时间。
除非您选择忽略此类异常,否则您无法简单地使用日期和时间。您需要时区的上下文来表示日期+时间。
仅在日期时间工作中的日期和时间通常被称为&#34;本地日期时间&#34;意味着任何位置,而不是特定的位置。因此,这不代表时刻,即时间轴上的一个点。关于一系列可能的时间跨度超过26小时的本地日期时间,时区比UTC提前14小时,落后12小时。应用时区来确定实际时刻,即时间线上的特定点。