gpt4 book ai didi

JAVA & Joda Time API : compare intervals, 检测重叠并生成新的间隔

转载 作者:搜寻专家 更新时间:2023-11-01 01:51:51 25 4
gpt4 key购买 nike

我正在做一个让我现在非常困惑的项目。

给定一个 List<TimeInterval> list包含类 TimeInterval 的元素,看起来像这样:

public class TimeInterval {
private static final Instant CONSTANT = new Instant(0);
private final LocalDate validFrom;
private final LocalDate validTo;


public TimeInterval(LocalDate validFrom, LocalDate validTo) {
this.validFrom = validFrom;
this.validTo = validTo;
}


public boolean isValid() {
try {
return toInterval() != null;
}
catch (IllegalArgumentException e) {
return false;
}
}


public boolean overlapsWith(TimeInterval timeInterval) {
return this.toInterval().overlaps(timeInterval.toInterval());
}


private Interval toInterval() throws IllegalArgumentException {
return new Interval(validFrom.toDateTime(CONSTANT), validTo.toDateTime(CONSTANT));
}

间隔是使用以下内容生成的:

TimeInterval tI = new TimeInterval(ld_dateValidFrom, ld_dateValidTo);

列表中的间隔可能重叠:

|--------------------|
|-------------------|

这应该导致:

|-------||-----------||------|

它应该不会导致:

|--------|-----------|-------|

一般来说,在数字上:

I1: 2014-01-01 - 2014-01-30
I2: 2014-01-07 - 2014-01-15

这应该导致:

I1: 2014-01-01 - 2014-01-06
I2: 2014-01-07 - 2014-01-15
I3: 2014-01-16 - 2014-01-30

我正在使用 JODA Time API 但由于我是第一次使用,所以我实际上并不知道如何解决我的问题。我已经看过方法 overlap() / overlapWith()但我还是不明白。

非常感谢您的帮助!

更新我发现了与我的问题类似的问题 >here<但这暂时对我没有帮助。


我一遍又一遍地尝试它,尽管它在我测试的第一个间隔内有效,但它实际上并没有按照我想要的方式工作。

这是我得到的间隔:

2014-10-20 ---> 2014-10-26
2014-10-27 ---> 2014-11-02
2014-11-03 ---> 2014-11-09
2014-11-10 ---> 2014-11-16
2014-11-17 ---> 9999-12-31

这是我用来生成新间隔的函数:

private List<Interval> cleanIntervalList(List<Interval> sourceList) {
TreeMap<DateTime, Integer> endPoints = new TreeMap<DateTime, Integer>();

// Fill the treeMap from the TimeInterval list. For each start point,
// increment the value in the map, and for each end point, decrement it.
for (Interval interval : sourceList) {
DateTime start = interval.getStart();
if (endPoints.containsKey(start)) {
endPoints.put(start, endPoints.get(start)+1);
}
else {
endPoints.put(start, 1);
}
DateTime end = interval.getEnd();
if (endPoints.containsKey(end)) {
endPoints.put(end, endPoints.get(start)-1);
}
else {
endPoints.put(end, 1);
}
}
System.out.println(endPoints);

int curr = 0;
DateTime currStart = null;

// Iterate over the (sorted) map. Note that the first iteration is used
// merely to initialize curr and currStart to meaningful values, as no
// interval precedes the first point.

List<Interval> targetList = new LinkedList<Interval>();

for (Entry<DateTime, Integer> e : endPoints.entrySet()) {
if (curr > 0) {
if (e.getKey().equals(endPoints.lastEntry().getKey())){
targetList.add(new Interval(currStart, e.getKey()));
}
else {
targetList.add(new Interval(currStart, e.getKey().minusDays(1)));
}
}
curr += e.getValue();
currStart = e.getKey();
}
System.out.println(targetList);
return targetList;
}

实际输出是这样的:

2014-10-20 ---> 2014-10-25
2014-10-26 ---> 2014-10-26
2014-10-27 ---> 2014-11-01
2014-11-02 ---> 2014-11-02
2014-11-03 ---> 2014-11-08
2014-11-09 ---> 2014-11-09
2014-11-10 ---> 2014-11-15
2014-11-16 ---> 2014-11-16
2014-11-17 ---> 9999-12-31

这就是输出应该的样子:

2014-10-20 ---> 2014-10-26
2014-10-27 ---> 2014-11-02
2014-11-03 ---> 2014-11-09
2014-11-10 ---> 2014-11-16
2014-11-17 ---> 9999-12-31

由于原始间隔没有重叠,我不明白为什么它会产生类似的东西

2014-10-26 ---> 2014-10-26
2014-11-02 ---> 2014-11-02
2014-11-09 ---> 2014-11-09
etc

我一整天都在努力解决这个问题,但我仍然没有成功:(非常感谢您的帮助!

最佳答案

半开

我建议您重新考虑您的目标条款。 Joda-Time明智地使用“半开”方法来定义时间跨度。开始是包容性,而结尾是排他性。例如,一周从第一天开始,一直到下一周的第一刻,但不包括。正如其他答案中所讨论的那样,半开被证明是处理时间跨度的非常有用和自然的方式。

enter image description here

在您的示例中使用这种半开方法,您确实想要这样的结果:

|--------|-----------|-------|

I1: 2014-01-01 - 2014-01-07
I2: 2014-01-07 - 2014-01-16
I3: 2014-01-16 - 2014-01-30

在 StackOverflow 中搜索“half-open”以查找讨论和示例,例如 this answer我的。

Joda 时间间隔

Joda-Time 具有出色的 Interval类来表示由时间轴上的一对端点定义的时间跨度。该 Interval 类提供了 overlapoverlaps (sic)、abutsgap 方法。特别注意 overlap比较其他两个时生成新 Interval 的方法;这可能是您解决方案的关键。

但不幸的是,该类仅适用于 DateTime对象而不是 LocalDate (仅限日期,没有时间或时区)。或许正是由于缺乏对 LocalDate 的支持,您或您的团队才发明了 TimeInterval 类。但我更建议使用该自定义类,考虑将 DateTime 对象与 Joda-Time 的类一起使用。我不能 100% 确定这比滚动您自己的仅限日期的间隔类更好(我很想这样做),但我的直觉告诉我是这样。

要关注日期而不是日期+时间,请在您的 DateTime 对象上调用 withTimeAtStartOfDay将时间部分调整到一天中第一时刻的方法。第一时刻通常是 00:00:00.000 但不一定是由于夏令时 (DST) 和其他可能的异常情况。请注意并与时区保持一致;可能始终使用 UTC。

这是 Joda-Time 2.5 中使用问题中建议的值的一些示例代码。在这些特定的行中,调用 withTimeAtStartOfDay 可能是不必要的,因为 Joda-Time 在没有提供日期的情况下默认为一天中的第一时刻。但我建议使用对 withTimeAtStartOfDay 的调用,因为它可以让您的代码根据您的意图自行记录。它使您所有以日常为重点的 DateTime 代码使用保持一致。

Interval i1 = new Interval( new DateTime( "2014-01-01", DateTimeZone.UTC ).withTimeAtStartOfDay(), new DateTime( "2014-01-30", DateTimeZone.UTC ).withTimeAtStartOfDay() );
Interval i2 = new Interval( new DateTime( "2014-01-07", DateTimeZone.UTC ).withTimeAtStartOfDay(), new DateTime( "2014-01-15", DateTimeZone.UTC ).withTimeAtStartOfDay() );

从那里开始,应用其他答案中建议的逻辑。

关于JAVA & Joda Time API : compare intervals, 检测重叠并生成新的间隔,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26516765/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com