Skip to content

Commit

Permalink
Use instant for free/busy calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
benfortuna committed Aug 15, 2019
1 parent 0dff111 commit ef89f76
Showing 1 changed file with 40 additions and 43 deletions.
83 changes: 40 additions & 43 deletions src/main/java/net/fortuna/ical4j/model/component/VFreeBusy.java
Expand Up @@ -41,13 +41,12 @@
import net.fortuna.ical4j.validate.component.VFreeBusyPublishValidator;
import net.fortuna.ical4j.validate.component.VFreeBusyReplyValidator;
import net.fortuna.ical4j.validate.component.VFreeBusyRequestValidator;
import org.threeten.extra.Interval;

import java.time.ZonedDateTime;
import java.time.Instant;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAmount;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.*;

/**
* $Id$ [Apr 5, 2004]
Expand Down Expand Up @@ -252,15 +251,15 @@ public VFreeBusy(final Temporal start, final Temporal end) {
// Within the "VFREEBUSY" calendar component, this property defines the
// start date and time for the free or busy time information. The time
// MUST be specified in UTC time.
getProperties().add(new DtStart(start, true));
getProperties().add(new DtStart<>(start));

// 4.8.2.2 Date/Time End
//
// Within the "VFREEBUSY" calendar component, this property defines the
// end date and time for the free or busy time information. The time
// MUST be specified in the UTC time format. The value MUST be later in
// time than the value of the "DTSTART" property.
getProperties().add(new DtEnd(end, true));
getProperties().add(new DtEnd<>(end));
}

/**
Expand All @@ -270,23 +269,23 @@ public VFreeBusy(final Temporal start, final Temporal end) {
* @param end the ending boundary for the VFreeBusy
* @param duration the length of the period being requested
*/
public VFreeBusy(final Temporal start, final Temporal end, final TemporalAmount duration) {
public VFreeBusy(final Instant start, final Instant end, final TemporalAmount duration) {
this();

// 4.8.2.4 Date/Time Start:
//
// Within the "VFREEBUSY" calendar component, this property defines the
// start date and time for the free or busy time information. The time
// MUST be specified in UTC time.
getProperties().add(new DtStart(start, true));
getProperties().add(new DtStart<>(start));

// 4.8.2.2 Date/Time End
//
// Within the "VFREEBUSY" calendar component, this property defines the
// end date and time for the free or busy time information. The time
// MUST be specified in the UTC time format. The value MUST be later in
// time than the value of the "DTSTART" property.
getProperties().add(new DtEnd(end, true));
getProperties().add(new DtEnd<>(end));

getProperties().add(new Duration(duration));
}
Expand Down Expand Up @@ -317,21 +316,21 @@ public VFreeBusy(final VFreeBusy request, final ComponentList<CalendarComponent>
// Within the "VFREEBUSY" calendar component, this property defines the
// start date and time for the free or busy time information. The time
// MUST be specified in UTC time.
getProperties().add(new DtStart(start.getDate(), true));
getProperties().add(new DtStart<>(start.getDate()));

// 4.8.2.2 Date/Time End
//
// Within the "VFREEBUSY" calendar component, this property defines the
// end date and time for the free or busy time information. The time
// MUST be specified in the UTC time format. The value MUST be later in
// time than the value of the "DTSTART" property.
getProperties().add(new DtEnd(end.getDate(), true));
getProperties().add(new DtEnd<>(end.getDate()));

if (duration != null) {
getProperties().add(new Duration(duration.getDuration()));
// Initialise with all free time of at least the specified duration..
final ZonedDateTime freeStart = ZonedDateTime.from(start.getDate());
final ZonedDateTime freeEnd = ZonedDateTime.from(end.getDate());
final Instant freeStart = Instant.from(start.getDate());
final Instant freeEnd = Instant.from(end.getDate());
final FreeBusy fb = new FreeTimeBuilder().start(freeStart)
.end(freeEnd)
.duration(duration.getDuration())
Expand All @@ -343,8 +342,8 @@ public VFreeBusy(final VFreeBusy request, final ComponentList<CalendarComponent>
}
else {
// initialise with all busy time for the specified period..
final ZonedDateTime busyStart = ZonedDateTime.from(start.getDate());
final ZonedDateTime busyEnd = ZonedDateTime.from(end.getDate());
final Instant busyStart = Instant.from(start.getDate());
final Instant busyEnd = Instant.from(end.getDate());
final FreeBusy fb = new BusyTimeBuilder().start(busyStart)
.end(busyEnd)
.components(components)
Expand All @@ -363,18 +362,18 @@ public VFreeBusy(final VFreeBusy request, final ComponentList<CalendarComponent>
*/
private class BusyTimeBuilder {

private Temporal start;
private Instant start;

private Temporal end;
private Instant end;

private ComponentList<CalendarComponent> components;

public BusyTimeBuilder start(Temporal start) {
public BusyTimeBuilder start(Instant start) {
this.start = start;
return this;
}

public BusyTimeBuilder end(Temporal end) {
public BusyTimeBuilder end(Instant end) {
this.end = end;
return this;
}
Expand All @@ -385,13 +384,11 @@ public BusyTimeBuilder components(ComponentList<CalendarComponent> components) {
}

public FreeBusy build() {
final PeriodList periods = getConsumedTime(components, start, end);
final DateRange range = new DateRange(start, end);
// periods must be in UTC time for freebusy..
periods.setUtc(true);
final List<Period<Instant>> periods = getConsumedTime(components, start, end);
periods.removeIf(period -> {
// check if period outside bounds..
return !range.intersects(period);
return !period.intersects(new Period<>(start, end));
});
return new FreeBusy(periods);
}
Expand All @@ -405,20 +402,20 @@ public FreeBusy build() {
*/
private class FreeTimeBuilder {

private ZonedDateTime start;
private Instant start;

private ZonedDateTime end;
private Instant end;

private TemporalAmount duration;

private ComponentList<CalendarComponent> components;

public FreeTimeBuilder start(ZonedDateTime start) {
public FreeTimeBuilder start(Instant start) {
this.start = start;
return this;
}

public FreeTimeBuilder end(ZonedDateTime end) {
public FreeTimeBuilder end(Instant end) {
this.end = end;
return this;
}
Expand All @@ -436,27 +433,27 @@ public FreeTimeBuilder components(ComponentList<CalendarComponent> components) {
public FreeBusy build() {
final FreeBusy fb = new FreeBusy();
fb.getParameters().add(FbType.FREE);
final PeriodList periods = getConsumedTime(components, start, end);
final DateRange<ZonedDateTime> range = new DateRange<>(start, end);
final List<Period<Instant>> periods = getConsumedTime(components, start, end);
final Interval interval = Interval.of(start, end);
// Add final consumed time to avoid special-case end-of-list processing
periods.add(new Period(end, end));
ZonedDateTime lastPeriodEnd = ZonedDateTime.from(start);
periods.add(new Period<>(end, end));
Instant lastPeriodEnd = start;
// where no time is consumed set the last period end as the range start..
for (final Period period : periods) {
for (final Period<Instant> period : periods) {
// check if period outside bounds.. or period intersects with the end of the range..
if (range.contains(period) ||
(range.intersects(period)
&& ZonedDateTime.from(period.getRangeStart()).isAfter(range.getRangeStart()))) {
if (interval.encloses(period.toInterval()) ||
(interval.overlaps(period.toInterval())
&& Instant.from(period.getStart()).isAfter(Instant.from(interval.getStart())))) {

// calculate duration between this period start and last period end..
final Duration freeDuration = new Duration(lastPeriodEnd, period.getStart());
if (new TemporalAmountComparator().compare(freeDuration.getDuration(), duration) >= 0) {
fb.getPeriods().add(new Period(lastPeriodEnd, freeDuration.getDuration()));
fb.getPeriods().add(new Period<>(lastPeriodEnd, freeDuration.getDuration()));
}
}

if (ZonedDateTime.from(period.getEnd()).isAfter(lastPeriodEnd)) {
lastPeriodEnd = ZonedDateTime.from(period.getEnd());
if (Instant.from(period.getEnd()).isAfter(lastPeriodEnd)) {
lastPeriodEnd = period.getEnd();
}
}
return fb;
Expand All @@ -468,15 +465,15 @@ public FreeBusy build() {
* @param components
* @return
*/
private PeriodList getConsumedTime(final ComponentList<CalendarComponent> components, final Temporal rangeStart,
final Temporal rangeEnd) {
private <T extends Temporal> List<Period<T>> getConsumedTime(final ComponentList<CalendarComponent> components, final T rangeStart,
final T rangeEnd) {

final PeriodList periods = new PeriodList();
final PeriodList<T> periods = new PeriodList<>();
// only events consume time..
for (final Component event : components.getComponents(Component.VEVENT)) {
periods.addAll(((VEvent) event).getConsumedTime(rangeStart, rangeEnd, false));
}
return periods.normalise();
return new ArrayList<>(periods.normalise().getPeriods());
}

/**
Expand Down Expand Up @@ -542,7 +539,7 @@ public final void validate(final boolean recurse) throws ValidationException {
}

if (dtStart != null && dtEnd != null
&& !ZonedDateTime.from(dtStart.getDate()).isBefore(ZonedDateTime.from(dtEnd.getDate()))) {
&& !Instant.from(dtStart.getDate()).isBefore(Instant.from(dtEnd.getDate()))) {
throw new ValidationException("Property [" + Property.DTEND
+ "] must be later in time than [" + Property.DTSTART + "]");
}
Expand Down

0 comments on commit ef89f76

Please sign in to comment.