/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.util.time;
import org.threeten.bp.LocalDate;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.financial.convention.daycount.DayCount;
import com.opengamma.financial.convention.daycount.DayCounts;
import com.opengamma.util.ArgumentChecker;
/**
* Converts dates to 'Analytics Time'. The latter are stored as doubles,
* and typically represent the fraction of years between some date and the current one.
*/
public final class TimeCalculatorBUS252 {
/**
* The day count used to convert to time.
*/
private static final DayCount MODEL_DAYCOUNT;
static {
/*
* Initialise MODEL_DAYCOUNT to BUSINESS_252
*/
MODEL_DAYCOUNT = DayCounts.BUSINESS_252;
}
private TimeCalculatorBUS252() {
}
/**
* Computes the time between two dates using a user-supplied day count convention. Dates can be in any order.
* If date1 is after date2, the result will be negative.
* @param date1 The first date.
* @param date2 The second date.
* @param dayCount The day count.
* @param calendar the calendar.
* @return The time.
*/
public static double getTimeBetween(final ZonedDateTime date1, final ZonedDateTime date2, final DayCount dayCount, final Calendar calendar) {
ArgumentChecker.notNull(date1, "date1");
ArgumentChecker.notNull(date1, "date2");
ArgumentChecker.notNull(dayCount, "day count");
ArgumentChecker.notNull(calendar, "calendar");
// Implementation note: here we convert date2 to the same zone as date1 so we don't accidentally gain or lose a day.
final ZonedDateTime rebasedDate2 = date2.withZoneSameInstant(date1.getZone());
final boolean timeIsNegative = date1.isAfter(rebasedDate2); // date1 >= date2
if (!timeIsNegative) {
return dayCount.getDayCountFraction(date1, rebasedDate2, calendar);
}
return -1.0 * dayCount.getDayCountFraction(rebasedDate2, date1, calendar);
}
/**
* Computes the time between two dates using a user-supplied day count convention. Dates can be in any order.
* If date1 is after date2, the result will be negative.
* @param date1 The first date.
* @param date2 The second date.
* @param dayCount The day count.
* @return The time.
*/
public static double getTimeBetween(final ZonedDateTime date1, final ZonedDateTime date2, final DayCount dayCount) {
ArgumentChecker.notNull(date1, "date1");
ArgumentChecker.notNull(date1, "date2");
ArgumentChecker.notNull(dayCount, "day count");
// Implementation note: here we convert date2 to the same zone as date1 so we don't accidentally gain or lose a day.
final ZonedDateTime rebasedDate2 = date2.withZoneSameInstant(date1.getZone());
final boolean timeIsNegative = date1.isAfter(rebasedDate2); // date1 >= date2
if (!timeIsNegative) {
return dayCount.getDayCountFraction(date1, rebasedDate2);
}
return -1.0 * dayCount.getDayCountFraction(rebasedDate2, date1);
}
/**
* Computes the time between two dates. Dates can be in any order. If date1 is after date2, the result will be negative.
* @param date1 The first date.
* @param date2 The second date.
* @param calendar the calendar.
* @return The time.
*/
public static double getTimeBetween(final ZonedDateTime date1, final ZonedDateTime date2, final Calendar calendar) {
return getTimeBetween(date1, date2, MODEL_DAYCOUNT, calendar);
}
/**
* Computes the time between two arrays of dates.
* @param date1 The first dates array.
* @param date2 The second dates array.
* @param calendar the calendar.
* @return The times.
*/
public static double[] getTimeBetween(final ZonedDateTime[] date1, final ZonedDateTime[] date2, final Calendar calendar) {
ArgumentChecker.notNull(date1, "First date");
ArgumentChecker.notNull(date2, "Second date");
ArgumentChecker.notNull(calendar, "calendar");
final int nbDates = date1.length;
ArgumentChecker.isTrue(nbDates == date2.length, "Number of dates should be equal");
final double[] result = new double[nbDates];
for (int loopdate = 0; loopdate < nbDates; loopdate++) {
result[loopdate] = getTimeBetween(date1[loopdate], date2[loopdate], calendar);
}
return result;
}
/**
* Computes the time between a given date and an array of dates. The same first date is used for all computations.
* @param date1 The first date.
* @param date2 The second dates array.
* @param calendar the calendar.
* @return The times.
*/
public static double[] getTimeBetween(final ZonedDateTime date1, final ZonedDateTime[] date2, final Calendar calendar) {
ArgumentChecker.notNull(date1, "First date");
ArgumentChecker.notNull(date2, "Second date");
final int nbDates = date2.length;
final double[] result = new double[nbDates];
for (int loopdate = 0; loopdate < nbDates; loopdate++) {
result[loopdate] = getTimeBetween(date1, date2[loopdate], calendar);
}
return result;
}
public static double getTimeBetween(final LocalDate date1, final LocalDate date2, final Calendar calendar) {
ArgumentChecker.notNull(date1, "date1");
ArgumentChecker.notNull(date2, "date2");
return getTimeBetween(date1.atStartOfDay(ZoneOffset.UTC), date2.atStartOfDay(ZoneOffset.UTC), calendar);
}
public static double getTimeBetween(final ZonedDateTime zdt1, final LocalDate date2, final Calendar calendar) {
ArgumentChecker.notNull(zdt1, "date1");
ArgumentChecker.notNull(date2, "date2");
final ZonedDateTime zdt2 = date2.atStartOfDay(ZoneOffset.UTC);
final ZonedDateTime rebasedZdt1 = zdt1.withZoneSameInstant(ZoneOffset.UTC);
return getTimeBetween(rebasedZdt1, zdt2, calendar);
}
public static double getTimeBetween(final LocalDate date1, final ZonedDateTime zdt2, final Calendar calendar) {
ArgumentChecker.notNull(date1, "date1");
ArgumentChecker.notNull(zdt2, "date2");
final ZonedDateTime zdt1 = date1.atStartOfDay(ZoneOffset.UTC);
final ZonedDateTime rebasedZdt2 = zdt2.withZoneSameInstant(ZoneOffset.UTC);
return getTimeBetween(zdt1, rebasedZdt2, calendar);
}
}