/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.basics.date; import static com.opengamma.strata.basics.date.LocalDateUtils.plusDays; import java.time.LocalDate; import java.time.YearMonth; import org.joda.convert.FromString; import org.joda.convert.ToString; import com.opengamma.strata.collect.ArgChecker; import com.opengamma.strata.collect.named.ExtendedEnum; import com.opengamma.strata.collect.named.Named; /** * A series of dates identified by name. * <p> * This interface encapsulates a sequence of dates as used in standard financial instruments. * The most common are the quarterly IMM dates, which are on the third Wednesday of March, * June, September and December. * <p> * The most common implementations are provided in {@link DateSequences}. * <p> * Note that the dates produced by the sequence may not be business days. * The application of a holiday calendar is typically the responsibility of the caller. * <p> * All implementations of this interface must be immutable and thread-safe. */ public interface DateSequence extends Named { /** * Obtains an instance from the specified unique name. * * @param uniqueName the unique name * @return the date sequence * @throws IllegalArgumentException if the name is not known */ @FromString public static DateSequence of(String uniqueName) { return extendedEnum().lookup(uniqueName); } /** * Gets the extended enum helper. * <p> * This helper allows instances of the sequence to be looked up. * It also provides the complete set of available instances. * * @return the extended enum helper */ public static ExtendedEnum<DateSequence> extendedEnum() { return DateSequences.ENUM_LOOKUP; } //------------------------------------------------------------------------- /** * Finds the next date in the sequence, always returning a date later than the input date. * <p> * Given an input date, this method returns the next date after it from the sequence. * * @param date the input date * @return the next sequence date after the input date * @throws IllegalArgumentException if there are no more sequence dates */ public default LocalDate next(LocalDate date) { LocalDate next = plusDays(date, 1); return nextOrSame(next); } /** * Finds the next date in the sequence, returning the input date if it is a date in the sequence. * <p> * Given an input date, this method returns a date from the sequence. * If the input date is in the sequence, it is returned. * Otherwise, the next date in the sequence after the input date is returned. * * @param date the input date * @return the input date if it is a sequence date, otherwise the next sequence date * @throws IllegalArgumentException if there are no more sequence dates */ public abstract LocalDate nextOrSame(LocalDate date); //------------------------------------------------------------------------- /** * Finds the nth date in the sequence after the input date, * always returning a date later than the input date. * <p> * Given an input date, this method returns a date from the sequence. * If the sequence number is 1, then the first date in the sequence after the input date is returned. * <p> * If the sequence number is 2 or larger, then the date referred to by sequence number 1 * is calculated, and the nth matching sequence date after that date returned. * * @param date the input date * @param sequenceNumber the 1-based index of the date to find * @return the nth sequence date after the input date * @throws IllegalArgumentException if the sequence number is zero or negative or if there are no more sequence dates */ public default LocalDate nth(LocalDate date, int sequenceNumber) { ArgChecker.notNegativeOrZero(sequenceNumber, "sequenceNumber"); if (sequenceNumber == 1) { return next(date); } else { return nth(next(date), sequenceNumber - 1); } } /** * Finds the nth date in the sequence on or after the input date, * returning the input date if it is a date in the sequence. * <p> * Given an input date, this method returns a date from the sequence. * If the sequence number is 1, then either the input date or the first date * in the sequence after the input date is returned. * <p> * If the sequence number is 2 or larger, then the date referred to by sequence number 1 * is calculated, and the nth matching sequence date after that date returned. * * @param date the input date * @param sequenceNumber the 1-based index of the date to find * @return the nth sequence date on or after the input date * @throws IllegalArgumentException if the sequence number is zero or negative or if there are no more sequence dates */ public default LocalDate nthOrSame(LocalDate date, int sequenceNumber) { ArgChecker.notNegativeOrZero(sequenceNumber, "sequenceNumber"); if (sequenceNumber == 1) { return nextOrSame(date); } else { return nth(nextOrSame(date), sequenceNumber - 1); } } //------------------------------------------------------------------------- /** * Finds the date in the sequence that corresponds to the specified year-month. * <p> * Given an input month, this method returns the date from the sequence that is associated with the year-month. * In most cases, the returned date will be in the same month as the input month, * but this is not guaranteed. * * @param yearMonth the input year-month * @return the next sequence date after the input date * @throws IllegalArgumentException if there are no more sequence dates */ public abstract LocalDate dateMatching(YearMonth yearMonth); //------------------------------------------------------------------------- /** * Gets the name that uniquely identifies this sequence. * <p> * This name is used in serialization and can be parsed using {@link #of(String)}. * * @return the unique name */ @ToString @Override public abstract String getName(); }