Java:日期比较

时间:2017-06-10 07:25:20

标签: java date

我有两张表Previous_ScheduleNew_Schedule。两个表都有3列:
Objective_IDSTART_DATEEND_DATE

我需要创建一个包含3列的NOT_PRESENT_IN_PREVIOUS_SCHEDULE表:
Objective_IDSTART_DATEEND_DATE

如果Previous Schedule的样本数据为:

Objective_id --Start_Date -- End_Date
1 -- 10-Jan-2014 -- 20-Jan-2014

如果New_Schedule的样本数据为:

Objective_id -- Start_Date -- End_Date
1 -- 12-Jan-2014 -- 15-Jan-2014

根据上述情况,我的NOT_PRESENT_IN_PREVIOUS_SCHEDULE应具有以下数据:

Objective_id -- Start_Date --End_Date
1 -- 10-Jan-2014 -- 11-Jan-2014
1 -- 16-Jan-2014 -- 20-Jan-2014

具有NOT_PRESENT_IN_PREVIOUS_SCHEDULE输出的逻辑应该用Java实现。对于任何类型的PREVIOUS_SCHEDULENEW_SCHEDULE,它应该是通用的,作为输入返回NOT_PRESENT_IN_PREVIOUS_SCHEDULE作为输出。

2 个答案:

答案 0 :(得分:0)

要将日期字符串转换为Java日期对象,可以使用SimpleDateFormat类。 Java 7的解决方案:

String string = "20-Jan-2014";
DateFormat format = new SimpleDateFormat("dd-MMM-yyyy", Locale.ENGLISH);
Date date = format.parse(string);

对于Java 8,您可以找到solution here

要计算两个日期之间的差异,您可以使用this operation

long diff = date2.getTime() - date1.getTime();
System.out.println ("Days: " + TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS));

计算Previous_ScheduleNew_Schedule之间的差异

如何解决此问题的想法可能是将Previous_Schedule中的日期转换为单个日期,存储在集合中。

Set<String> dates = new HashSet<String>();
dates.add( "10-Jan-2014" );
dates.add( "11-Jan-2014" );
dates.add( "12-Jan-2014" );
...
dates.add( "20-Jan-2014" );

然后从Set:

中删除New_Schedule中句点的日期
dates.remove( "12-Jan-2014" );
...
dates.remove( "15-Jan-2014" );

集合中的其余元素将为创建NOT_PRESENT_IN_PREVIOUS_SCHEDULE提供基础。

您可以将日期对象添加到Set中,而不是使用字符串:

Set<Date> dates = new HashSet<Date>();
dates.add( date1 );

如何将10-Jan-2014 -- 20-Jan-2014之类的日期转换为单个日期以及如何执行反向任务以创建NOT_PRESENT_IN_PREVIOUS_SCHEDULE应该来自您自己的创造力。提示:您可以使用循环来解决该任务。

答案 1 :(得分:0)

这是我的建议。以下方法通过从第一个列表中删除第二个列表中的日期间隔来“减去”两个计划列表。它使用双循环,它首先迭代第二个列表中的计划,应该减去那些计划。对于每个这样的计划,它从第一个列表中的每个计划中减去它,构建一个新的结果计划列表。

public static List<Schedule> scheduleListDiff(
        List<Schedule> schedules, List<Schedule> schedulesToExclude) {
    // eliminate dates from schedulesToExclude one schdule at a time
    for (Schedule toExclude : schedulesToExclude) {
        List<Schedule> result = new ArrayList<>();
        for (Schedule originalSchedule : schedules) {
            result.addAll(originalSchedule.notPresentIn(toExclude));
        }
        schedules = result;
    }
    return schedules;
}

您可以这样称呼

    List<Schedule> notPresentInPreviousSchedule 
            = scheduleListDiff(previousSchedules, newSchedules);

使用您问题中的列表,结果是所需的

1 -- 10-Jan-2014 -- 11-Jan-2014
1 -- 16-Jan-2014 -- 20-Jan-2014

我已使用辅助方法Schedule拟合notPresentIn()类来执行实际比较:

/** @return a list of 0, 1 or 2 schedules with the dates from this schedule that are not in other */
List<Schedule> notPresentIn(Schedule other) {
    if (other.end.isBefore(start) || end.isBefore(other.start)) { // no overlap
        return Collections.singletonList(this);
    }
    // now we know there is an overlap
    List<Schedule> result = new ArrayList<>(2);
    if (start.isBefore(other.start)) { // need to include day/s from the first part of this
        // this bit must end the day before other.start
        result.add(new Schedule(objectiveId, start, other.start.minusDays(1)));
    }
    if (end.isAfter(other.end)) { // need day/s from the last part
        result.add(new Schedule(objectiveId, other.end.plusDays(1), end));
    }
    return result;
}

我没有彻底测试过,某处可能很容易出现错误,但我希望这能让你开始。

我没有考虑效率。如果您有数百万个计划,您可以从更复杂的算法中受益,该算法首先按时间顺序对计划进行排序,因此您无需将每个计划从一个列表与另一个列表的每个计划进行比较。有几百个时间表我很怀疑你需要照顾。

我使用java.time.LocalDate作为Schedule类中的日期:

int objectiveId;
// dates are inclusive; end is on or after start
LocalDate start;
LocalDate end;

修改:我在重复问题find out cancelled period from given date的示例数据上运行了我的代码。该样本在一个先前的计划中有两个新的样本计划。因此,此前的时间表应分为三个。结果是:

107 -- 10 May 2016 -- 11 May 2016
107 -- 14 May 2016 -- 15 May 2016
107 -- 19 May 2016 -- 20 May 2016

这是有效的,因为scheduleListDiff()中的每次迭代都使用前一次迭代的结果,所以首先将调度分成两次,下一次迭代将进一步拆分。