jfxtras.icalendarfx.properties.component.recurrence.rrule.byxxx.ByYearDay Maven / Gradle / Ivy
package jfxtras.icalendarfx.properties.component.recurrence.rrule.byxxx;
import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
import jfxtras.icalendarfx.properties.component.recurrence.rrule.byxxx.ByRuleIntegerAbstract;
import jfxtras.icalendarfx.properties.component.recurrence.rrule.byxxx.ByYearDay;
/**
* By Year Day
* BYYEARDAY
* RFC 5545, iCalendar 3.3.10, page 42
*
* The BYYEARDAY rule part specifies a COMMA-separated list of days
of the year. Valid values are 1 to 366 or -366 to -1. For
example, -1 represents the last day of the year (December 31st)
and -306 represents the 306th to the last day of the year (March
1st). The BYYEARDAY rule part MUST NOT be specified when the FREQ
rule part is set to DAILY, WEEKLY, or MONTHLY.
*
* @author David Bal
*
*/
public class ByYearDay extends ByRuleIntegerAbstract
{
public ByYearDay()
{
super();
}
public ByYearDay(Integer... yearDays)
{
super(yearDays);
}
public ByYearDay(ByYearDay source)
{
super(source);
}
@Override
Predicate isValidValue()
{
return (value) -> (value >= -366) && (value <= 366) && (value != 0);
}
@Override
public Stream streamRecurrences(Stream inStream, ChronoUnit chronoUnit, Temporal dateTimeStart)
{
switch (chronoUnit)
{
case HOURS:
case MINUTES:
case SECONDS:
return inStream.filter(d ->
{ // filter out all but qualifying days
int myDayOfYear = d.get(ChronoField.DAY_OF_YEAR);
for (int dayOfYear : getValue())
{
if (dayOfYear > 0)
{
if (dayOfYear == myDayOfYear) return true;
} else
{ // handle negative days of year
Temporal firstDayOfNextYear = d.with(TemporalAdjusters.firstDayOfNextYear());
Period myNegativeDayOfYear = Period.between(LocalDate.from(firstDayOfNextYear), LocalDate.from(d));
if (Period.ofDays(dayOfYear).equals(myNegativeDayOfYear)) return true;
}
}
return false;
});
case YEARS:
return inStream.flatMap(d ->
{ // Expand to be include all days of year
List dates = new ArrayList<>();
for (int dayOfYear : getValue())
{
final Temporal correctYearTemporal = (dayOfYear > 0) ? d : d.minus(1, ChronoUnit.YEARS);
int daysInYear = (int) ChronoUnit.DAYS.between(correctYearTemporal.with(TemporalAdjusters.firstDayOfYear()),
correctYearTemporal.with(TemporalAdjusters.firstDayOfNextYear()));
int finalDayOfYear = 0;
if (dayOfYear > 0)
{
if (dayOfYear <= daysInYear)
{
finalDayOfYear = dayOfYear;
}
} else if (dayOfYear < 0)
{
int newDayOfYear = daysInYear + dayOfYear + 1;
if (newDayOfYear > 0)
{
finalDayOfYear = newDayOfYear;
}
} else
{
throw new IllegalArgumentException(name().toString() + " can't have a value of zero");
}
Temporal newTemporal = (finalDayOfYear != 0) ? correctYearTemporal.with(ChronoField.DAY_OF_YEAR, finalDayOfYear) : null;
if (newTemporal != null)
{
dates.add(newTemporal);
}
}
return dates.stream();
});
case DAYS:
case WEEKS:
case MONTHS:
throw new IllegalArgumentException(name().toString() + " is not available for " + chronoUnit + " frequency."); // Not available
default:
throw new IllegalArgumentException("Not implemented: " + chronoUnit);
}
}
public static ByYearDay parse(String content)
{
return ByYearDay.parse(new ByYearDay(), content);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy