/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util.time; import static org.threeten.bp.temporal.ChronoUnit.DAYS; import java.io.Serializable; import org.joda.convert.FromString; import org.joda.convert.ToString; import org.threeten.bp.Duration; import org.threeten.bp.Period; import org.threeten.bp.format.DateTimeParseException; import com.opengamma.util.ArgumentChecker; /** * A tenor. */ public class Tenor implements Comparable<Tenor>, Serializable { /** Serialization version. */ private static final long serialVersionUID = -6312355131513714559L; /** * An overnight tenor. * @deprecated use Tenor.ON */ @Deprecated public static final Tenor OVERNIGHT = new Tenor(Period.ofDays(1)); /** * A tenor of one day. */ public static final Tenor DAY = new Tenor(Period.ofDays(1)); /** * A tenor of one day. */ public static final Tenor ONE_DAY = new Tenor(Period.ofDays(1)); /** * A tenor of two days. */ public static final Tenor TWO_DAYS = new Tenor(Period.ofDays(2)); /** * A tenor of two days. */ public static final Tenor THREE_DAYS = new Tenor(Period.ofDays(3)); /** * A tenor of 1 week. */ public static final Tenor ONE_WEEK = new Tenor(Period.ofDays(7)); /** * A tenor of 2 weeks. */ public static final Tenor TWO_WEEKS = new Tenor(Period.ofDays(14)); /** * A tenor of 3 weeks. */ public static final Tenor THREE_WEEKS = new Tenor(Period.ofDays(21)); /** * A tenor of 6 weeks. */ public static final Tenor SIX_WEEKS = new Tenor(Period.ofDays(42)); /** * A tenor of 1 month. */ public static final Tenor ONE_MONTH = new Tenor(Period.ofMonths(1)); /** * A tenor of 2 months. */ public static final Tenor TWO_MONTHS = new Tenor(Period.ofMonths(2)); /** * A tenor of 3 months. */ public static final Tenor THREE_MONTHS = new Tenor(Period.ofMonths(3)); /** * A tenor of 4 months. */ public static final Tenor FOUR_MONTHS = new Tenor(Period.ofMonths(4)); /** * A tenor of 5 months. */ public static final Tenor FIVE_MONTHS = new Tenor(Period.ofMonths(5)); /** * A tenor of 6 months. */ public static final Tenor SIX_MONTHS = new Tenor(Period.ofMonths(6)); /** * A tenor of 7 months. */ public static final Tenor SEVEN_MONTHS = new Tenor(Period.ofMonths(7)); /** * A tenor of 8 months. */ public static final Tenor EIGHT_MONTHS = new Tenor(Period.ofMonths(8)); /** * A tenor of 9 months. */ public static final Tenor NINE_MONTHS = new Tenor(Period.ofMonths(9)); /** * A tenor of 10 months. */ public static final Tenor TEN_MONTHS = new Tenor(Period.ofMonths(10)); /** * A tenor of 11 months. */ public static final Tenor ELEVEN_MONTHS = new Tenor(Period.ofMonths(11)); /** * A tenor of 12 months. */ public static final Tenor TWELVE_MONTHS = new Tenor(Period.ofMonths(12)); /** * A tenor of 18 months. */ public static final Tenor EIGHTEEN_MONTHS = new Tenor(Period.ofMonths(18)); /** * A tenor of 1 year. */ public static final Tenor ONE_YEAR = new Tenor(Period.ofYears(1)); /** * A tenor of 2 years. */ public static final Tenor TWO_YEARS = new Tenor(Period.ofYears(2)); /** * A tenor of 3 years. */ public static final Tenor THREE_YEARS = new Tenor(Period.ofYears(3)); /** * A tenor of 4 years. */ public static final Tenor FOUR_YEARS = new Tenor(Period.ofYears(4)); /** * A tenor of 5 years. */ public static final Tenor FIVE_YEARS = new Tenor(Period.ofYears(5)); /** * A tenor of 6 years. */ public static final Tenor SIX_YEARS = new Tenor(Period.ofYears(6)); /** * A tenor of 7 years. */ public static final Tenor SEVEN_YEARS = new Tenor(Period.ofYears(7)); /** * A tenor of 8 years. */ public static final Tenor EIGHT_YEARS = new Tenor(Period.ofYears(8)); /** * A tenor of 9 years. */ public static final Tenor NINE_YEARS = new Tenor(Period.ofYears(9)); /** * A tenor of 10 years. */ public static final Tenor TEN_YEARS = new Tenor(Period.ofYears(10)); /** * A tenor of one working week (5 days). */ public static final Tenor WORKING_WEEK = new Tenor(Period.ofDays(5)); /** * A tenor of the days in a standard year (365 days). */ public static final Tenor YEAR = new Tenor(Period.ofDays(365)); /** * A tenor of the days in a leap year (366 days). */ public static final Tenor LEAP_YEAR = new Tenor(Period.ofDays(366)); /** * An overnight / next (O/N) tenor. */ public static final Tenor ON = new Tenor(BusinessDayTenor.OVERNIGHT); /** * A spot / next (S/N) tenor. */ public static final Tenor SN = new Tenor(BusinessDayTenor.SPOT_NEXT); /** * A tomorrow / next (a.k.a. tom next, T/N) tenor. */ public static final Tenor TN = new Tenor(BusinessDayTenor.TOM_NEXT); //------------------------------------------------------------------------- /** * Business day tenor. */ public enum BusinessDayTenor { /** * Overnight. */ OVERNIGHT(Period.ofDays(1)), /** * Tomorrow / next. */ TOM_NEXT(Period.ofDays(2)), /** * Spot / next. */ SPOT_NEXT(Period.ofDays(3)); /** The approximate duration of a business day tenor */ private final Duration _approximateDuration; /** * @param approximateDuration The approximate duration of a business day tenor. It is not * exact because there could be holidays in the period. */ private BusinessDayTenor(final Period approximateDuration) { _approximateDuration = DAYS.getDuration().multipliedBy(approximateDuration.getDays()); } /** * Gets the approximate duration. * @return The approximate duration */ public Duration getApproximateDuration() { return _approximateDuration; } } //------------------------------------------------------------------------- /** * The period of the tenor. */ private final Period _period; /** * The business day tenor. */ private final BusinessDayTenor _businessDayTenor; //------------------------------------------------------------------------- /** * Obtains a {@code Tenor} from a {@code Period}. * * @param period the period to convert to a tenor, not null * @return the tenor, not null */ public static Tenor of(final Period period) { ArgumentChecker.notNull(period, "period"); return new Tenor(period); } /** * Obtains a {@code Tenor} from a {@code BusinessDayTenor}. * * @param businessDayTenor the tenor to convert, not null * @return the tenor, not null */ public static Tenor of(final BusinessDayTenor businessDayTenor) { ArgumentChecker.notNull(businessDayTenor, "businessDayTenor"); return new Tenor(businessDayTenor); } /** * Parses a formatted string representing the tenor. * <p> * The format is based on ISO-8601, such as 'P3M'. * * @param tenorStr the string representing the tenor, not null * @return the tenor, not null */ @FromString @SuppressWarnings("deprecation") public static Tenor parse(final String tenorStr) { ArgumentChecker.notNull(tenorStr, "tenorStr"); try { return new Tenor(DateUtils.toPeriod(tenorStr)); } catch (DateTimeParseException e) { return new Tenor(BusinessDayTenor.valueOf(tenorStr)); } } //------------------------------------------------------------------------- /** * Creates a tenor. * @param period the period to represent * @deprecated Use the static factory method {@code Tenor.of(Period)}. */ @Deprecated public Tenor(final Period period) { ArgumentChecker.notNull(period, "period"); //change of behaviour _period = period; _businessDayTenor = null; } /** * Creates a tenor without a period. This is used for overnight, * spot next and tomorrow next tenors. */ private Tenor(final BusinessDayTenor businessDayTenor) { ArgumentChecker.notNull(businessDayTenor, "business day tenor"); _period = null; _businessDayTenor = businessDayTenor; } /** * Gets the tenor period. * @return the period * @throws IllegalStateException If the tenor is not backed by a {@link Period} */ public Period getPeriod() { if (_period == null) { throw new IllegalStateException("Could not get period for " + toString()); } return _period; } /** * Gets the business day tenor if the tenor is of appropriate type. * @return The business day tenor * @throws IllegalStateException If the tenor is backed by a period */ public BusinessDayTenor getBusinessDayTenor() { if (_businessDayTenor == null) { throw new IllegalStateException("Could not get business day tenor for " + toString()); } return _businessDayTenor; } /** * Returns true if the tenor is a business day tenor. * @return True if the tenor is a business day tenor */ public boolean isBusinessDayTenor() { return _period == null; } /** * Returns a tenor backed by a period of days. * @param days The number of days * @return The tenor */ public static final Tenor ofDays(final int days) { return new Tenor(Period.ofDays(days)); } /** * Returns a tenor backed by a period of weeks. * @param weeks The number of weeks * @return The tenor */ public static final Tenor ofWeeks(final int weeks) { return new Tenor(Period.ofDays(weeks * 7)); } /** * Returns a tenor backed by a period of months. * @param months The number of months * @return The tenor */ public static final Tenor ofMonths(final int months) { return new Tenor(Period.ofMonths(months)); // TODO: what do we do here } /** * Returns a tenor backed by a period of years. * @param years The number of years * @return The tenor */ public static final Tenor ofYears(final int years) { return new Tenor(Period.ofYears(years)); // TODO: what do we do here } /** * Returns a tenor of business days. * @param businessDayTenor The business day * @return The tenor */ public static final Tenor ofBusinessDay(final BusinessDayTenor businessDayTenor) { return new Tenor(businessDayTenor); } /** * Returns a tenor of business days. * @param businessDayTenor The business days name * @return The tenor */ public static final Tenor ofBusinessDay(final String businessDayTenor) { return new Tenor(BusinessDayTenor.valueOf(businessDayTenor)); } //------------------------------------------------------------------------- /** * Returns a formatted string representing the tenor. * <p> * The format is based on ISO-8601, such as 'P3M'. * * @return the formatted tenor, not null */ @ToString public String toFormattedString() { if (_period != null) { return getPeriod().toString(); } return getBusinessDayTenor().toString(); } //------------------------------------------------------------------------- @Override public int compareTo(final Tenor other) { final Duration thisDur, otherDur; if (_period == null) { thisDur = _businessDayTenor.getApproximateDuration(); } else { thisDur = DateUtils.estimatedDuration(_period); } if (other._period == null) { otherDur = other._businessDayTenor.getApproximateDuration(); } else { otherDur = DateUtils.estimatedDuration(other._period); } return thisDur.compareTo(otherDur); } @Override public boolean equals(final Object o) { if (o == null) { return false; } if (!(o instanceof Tenor)) { return false; } final Tenor other = (Tenor) o; if (_period == null) { if (other._period == null) { return _businessDayTenor == other._businessDayTenor; } return false; } if (other._period == null) { return false; } return _period.equals(other._period); } @Override public int hashCode() { if (_period == null) { return getBusinessDayTenor().hashCode(); } return getPeriod().hashCode(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Tenor["); if (_period == null) { sb.append(getBusinessDayTenor().toString()); } else { sb.append(getPeriod().toString()); } sb.append("]"); return sb.toString(); } }