package name.abuchen.portfolio.util; import java.time.LocalDate; import java.time.temporal.ChronoUnit; import java.util.Iterator; import java.util.NoSuchElementException; public final class Interval { private LocalDate start; private LocalDate end; private Interval(LocalDate start, LocalDate end) { this.start = start; this.end = end; } public static Interval of(LocalDate start, LocalDate end) { return new Interval(start, end); } public LocalDate getStart() { return start; } public LocalDate getEnd() { return end; } public boolean isLongerThan(Interval other) { return getDays() > other.getDays(); } public boolean contains(LocalDate other) { return other.isAfter(start) && !other.isAfter(end); } public long getDays() { return ChronoUnit.DAYS.between(start, end); } /** * Returns an Iterable with all the year contained in the interval. * Particularly, if the start of the interval is the last day of a year, * that year is not included. */ public Iterable<Integer> iterYears() { return () -> new Iterator<Integer>() { LocalDate index = LocalDate.of(start.plusDays(1).getYear(), 1, 1); @Override public boolean hasNext() { return !index.isAfter(end); } @Override public Integer next() { if (!hasNext()) throw new NoSuchElementException(); Integer answer = index.getYear(); index = index.plusYears(1); return answer; } }; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((end == null) ? 0 : end.hashCode()); result = prime * result + ((start == null) ? 0 : start.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Interval other = (Interval) obj; if (end == null) { if (other.end != null) return false; } else if (!end.equals(other.end)) return false; if (start == null) { if (other.start != null) return false; } else if (!start.equals(other.start)) return false; return true; } }