我有两张表Previous_Schedule
和New_Schedule
。两个表都有3列:
Objective_ID
,START_DATE
和END_DATE
。
我需要创建一个包含3列的NOT_PRESENT_IN_PREVIOUS_SCHEDULE
表:
Objective_ID
,START_DATE
和END_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_SCHEDULE
和NEW_SCHEDULE
,它应该是通用的,作为输入返回NOT_PRESENT_IN_PREVIOUS_SCHEDULE
作为输出。
答案 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_Schedule
和New_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()
中的每次迭代都使用前一次迭代的结果,所以首先将调度分成两次,下一次迭代将进一步拆分。