/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.util.time; import java.util.MissingResourceException; import java.util.ResourceBundle; import org.threeten.bp.LocalDate; import org.threeten.bp.ZoneOffset; import org.threeten.bp.ZonedDateTime; import com.opengamma.analytics.env.AnalyticsEnvironment; import com.opengamma.financial.convention.calendar.Calendar; import com.opengamma.financial.convention.daycount.DayCount; import com.opengamma.financial.convention.daycount.DayCountFactory; 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 TimeCalculator { /** * The day count used to convert to time. * @deprecated Should use {@link AnalyticsEnvironment} in preference. Will be removed in a later version. */ @Deprecated private static final DayCount MODEL_DAYCOUNT; static { /* * Initialise MODEL_DAYCOUNT to what is set in TimeCalculator.properties. * Deprecated, maintained for backwards compatibility. */ String modelDayCount = null; try { final ResourceBundle conventions = ResourceBundle.getBundle(TimeCalculator.class.getName()); modelDayCount = conventions.getString("MODEL_DAYCOUNT"); } catch (final MissingResourceException ex) { // pass } if (modelDayCount != null && DayCountFactory.of(modelDayCount) != null) { MODEL_DAYCOUNT = DayCountFactory.of(modelDayCount); } else { MODEL_DAYCOUNT = null; } } private TimeCalculator() { } /** * 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"); // 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. * @return The time. */ public static double getTimeBetween(final ZonedDateTime date1, final ZonedDateTime date2) { final DayCount dayCount = MODEL_DAYCOUNT != null ? MODEL_DAYCOUNT : AnalyticsEnvironment.getInstance().getModelDayCount(); return getTimeBetween(date1, date2, dayCount); } /** * Computes the time between two arrays of dates. * @param date1 The first dates array. * @param date2 The second dates array. * @return The times. */ public static double[] getTimeBetween(final ZonedDateTime[] date1, final ZonedDateTime[] date2) { ArgumentChecker.notNull(date1, "First date"); ArgumentChecker.notNull(date2, "Second date"); 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]); } 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. * @return The times. */ public static double[] getTimeBetween(final ZonedDateTime date1, final ZonedDateTime[] date2) { 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]); } return result; } public static double getTimeBetween(final LocalDate date1, final LocalDate date2) { ArgumentChecker.notNull(date1, "date1"); ArgumentChecker.notNull(date2, "date2"); return getTimeBetween(date1.atStartOfDay(ZoneOffset.UTC), date2.atStartOfDay(ZoneOffset.UTC)); } public static double getTimeBetween(final ZonedDateTime zdt1, final LocalDate date2) { 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); } public static double getTimeBetween(final LocalDate date1, final ZonedDateTime zdt2) { 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); } }