首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >检查日期范围是否触及某个时间范围

检查日期范围是否触及某个时间范围
EN

Stack Overflow用户
提问于 2017-02-03 12:48:29
回答 3查看 397关注 0票数 4

萨姆是一名兼职卡车司机。如果他从凌晨2点到0点6点开车,他会得到特别津贴。他的老板想知道这段时间里所有的旅行都发生了哪些变化。下面是他最后4次旅行的细节。

Trip 1:

StartDateTime :01-2017 00.15.00

EndDateTime :03-2017 01.45.00

感动:真

Trip 2:

StartDateTime :04-2017年1月-2017年13.00.00

EndDateTime :05-2017年1月-2017年13.00.00

感动:真

Trip 3:

StartDateTime :06-2017 00.00.00

EndDateTime :06-2017 05.00.00

感动:真

Trip 4:

StartDateTime :06-2017 06.01.00

EndDateTime :06-2017年1月-2017年23.00.00

触碰:假

我想出了自己的实现,用于在java中找到这个(如果情况很少),但我有一种感觉,那就是我正在重新发明轮子。如果日期范围接触到时间范围,那么最好的方法是什么?

编辑:添加以下方法

代码语言:javascript
复制
    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;
    }
EN

回答 3

Stack Overflow用户

发布于 2017-02-03 13:38:35

这个问题类似于循环值的交集。

如果您的解决方案使用了很多情况,请考虑三角学类比这里。利用余弦函数解决了逐日包裹和非平凡区间重叠的问题。

日期和时间可以转换成如下的角度

代码语言:javascript
复制
TimeAngle = Pi * TimeHrs / 12

请注意,时间范围和行程时间都应该“标准化”:

  • 如果行程持续时间超过一天,则应由0.2*Pi角度间隔代替。 在其他情况下:
    • 将旅程开始日期的00:00定义为0
    • 获得启动角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

票数 2
EN

Stack Overflow用户

发布于 2017-02-03 15:52:55

我应该先用代码把它写出来,因为我认为用毫秒时间戳来考虑这个问题可能会更简单(或者至少对我来说很熟悉)。如果我有时间的话,我还是可以回去的。

与此相关的是,我发现区间树是一本有趣的读物,尽管我并没有去追求它。

我不相信以下内容是正确的,特别是我关于如何选择0200/0600日期组件的“规则”。需要呻吟测试但是。。。

如果山姆开车20小时或更长时间进行一次旅行,那么他已经在某种程度上触及了时间范围。(例如Trips 1和2) 如果山姆每次旅行开车不到20个小时,那么我们可以利用他旅行的时间限制我们的可能性范围。 根据开始日期建立0200/0600的日期组件。如果startDateTime的时间组件在0000到0600之间(包括在内),那么0200/0600共享startDateTime的日期组件,否则就是第二天。

duration = endDateTime - startDateTime mustStartTime = 0200 - duration mustEndTime = 0600 + duration touched = (startDateTime >= mustStartTime && endDateTime <= mustEndTime)

旅行3

  • StartDateTime: 06-2017 00.00.00
  • EndDateTime: 06-2017 05.00.00
  • 感动:真

duration = 5 hours mustStartTime = 2100 = 0200 - 5 mustEndTime = 1100 = 0600 + 5 touched = (0000 >= 2100 && 0500 <= 1100) = (true && true)

旅行4

  • StartDateTime :06-2017 06.01.00
  • EndDateTime :06-2017年1月-2017年23.00.00
  • 触碰:假

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

  • StartDateTime :06-2017 03.00.00
  • EndDateTime :06-2017 04.00.00
  • 感动:真

duration = 1 hour mustStartTime = 0100 = 0200 - 1 hour mustEndTime = 0700 = 0600 + 1 hour touched = true = (0300 >= 0100 && 0400 <= 0700) = (true && true)

旅行6

  • StartDateTime :06-2017 00.00.00
  • EndDateTime :06-2017 01.30.00
  • 触碰:假

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

  • StartDateTime :06-2017 05.00.00
  • EndDateTime :06-2017 06.00.00
  • 感动:真

duration = 1 hour mustStartTime = 0100 = 0200 - 1 hour mustEndTime = 0700 = 0600 + 1 hour touched = (0500 >= 0100 && 0600 <= 0700) = (true && true)

更新

现在有代码和测试。所有的断言都是正确的!绝对感觉就像车轮的重新发明!

代码语言:javascript
复制
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));
    }

}
票数 0
EN

Stack Overflow用户

发布于 2017-02-03 19:59:55

这个问题还不完整。

异常

在日期工作中,我们会遇到异常。夏令时(DST)在最常见的。但我们也遇到了政客们经常重新定义时区的问题,就像过去几年在土耳其 (2016)、俄罗斯 (2016、2014、2011)、委内瑞拉 (2016,2007)以及其他地方所发生的那样。

所以你必须决定如何处理这些异常现象。例如,在DST切割器上,一天可以长达23或25个小时。在美国,DST指的是凌晨2点或凌晨2点两次。注意,DST切割发生在美国以外的其他地方。

时区

除非你选择忽略这些异常现象,否则你不能简单地处理日期和时间。您需要时区的上下文来确定date+time的含义。

仅在日期工作中的日期和时间通常被称为“本地日期-时间”,意指任何地点,而不是特定的地点。因此,这并不代表时间线上的某个时刻。一个当地的日期-时间,一个模糊的概念,对一系列可能的时刻,延伸超过26个小时,时区运行多达14个小时之前,世界协调时,12个小时后。应用时区来确定实际时刻,时间线上的特定点。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42024710

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档