package fr.openwide.core.commons.util.collections;
import java.io.Serializable;
import java.util.Date;
import org.joda.time.DateTimeFieldType;
import org.joda.time.DurationFieldType;
import org.joda.time.LocalDate;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import com.google.common.collect.Range;
/**
* Several discrete domains for dates.
* <p><strong>WARNING:</strong> When using these domains in a contiguous set, you <strong>must</strong>
* ensure that your range has been {@link PartitionDiscreteDomain#alignOut(Range) aligned} on this domain.
* Otherwise, you will experience infinite loops.
*/
public class DateDiscreteDomain extends PartitionDiscreteDomain<Date> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* @return A discrete domain for the first day of each month at midnight.
* <p><strong>WARNING:</strong> When using this domain in a contiguous set, you <strong>must</strong>
* ensure that your range has been {@link DateDiscreteDomain#alignOut(Range) aligned} on this domain.
* Otherwise, you will experience infinite loops.
*/
public static DateDiscreteDomain months() {
return MONTHS;
}
private static final DateDiscreteDomain MONTHS = new DateDiscreteDomain(DurationFieldType.months(), DateTimeFieldType.monthOfYear()) {
private static final long serialVersionUID = 1L;
private Object readResolve() {
return MONTHS;
}
@Override
public String toString() {
return "DateDiscreteDomain.months()";
}
};
/**
* @return A discrete domain for the first day of each week at midnight.
* <p><strong>WARNING:</strong> When using this domain in a contiguous set, you <strong>must</strong>
* ensure that your range has been {@link DateDiscreteDomain#align(Range) aligned} on this domain.
* Otherwise, you will experience infinite loops.
*/
public static DateDiscreteDomain weeks() {
return WEEKS;
}
private static final DateDiscreteDomain WEEKS = new DateDiscreteDomain(DurationFieldType.weeks(), DateTimeFieldType.weekOfWeekyear()) {
private static final long serialVersionUID = 1L;
private Object readResolve() {
return WEEKS;
}
@Override
public String toString() {
return "DateDiscreteDomain.weeks()";
}
};
private final DurationFieldType iterationFieldType;
private final DateTimeFieldType roundFieldType;
private final PeriodType periodType;
private DateDiscreteDomain(DurationFieldType iterationFieldType, DateTimeFieldType roundFloorFieldType) {
this.iterationFieldType = iterationFieldType;
this.roundFieldType = roundFloorFieldType;
this.periodType = PeriodType.forFields(new DurationFieldType[] { iterationFieldType });
}
@Override
public Date next(Date value) {
return internalAlignPrevious(value)
.withFieldAdded(iterationFieldType, 1).toDate();
}
@Override
public Date previous(Date value) {
return internalAlignNext(value)
.withFieldAdded(iterationFieldType, -1).toDate();
}
@Override
public long distance(Date start, Date end) {
return new Period(new LocalDate(start), new LocalDate(end), periodType).get(iterationFieldType);
}
@Override
public Date alignNext(Date value) {
return internalAlignNext(value).toDate();
}
@Override
public Date alignPrevious(Date value) {
return internalAlignPrevious(value).toDate();
}
private LocalDate internalAlignNext(Date value) {
return new LocalDate(value).property(roundFieldType).roundCeilingCopy();
}
private LocalDate internalAlignPrevious(Date value) {
return new LocalDate(value).property(roundFieldType).roundFloorCopy();
}
}