001/* 002 * ObjectLab, http://www.objectlab.co.uk/open is sponsoring the ObjectLab Kit. 003 * 004 * Based in London, we are world leaders in the design and development 005 * of bespoke applications for the securities financing markets. 006 * 007 * <a href="http://www.objectlab.co.uk/open">Click here to learn more</a> 008 * ___ _ _ _ _ _ 009 * / _ \| |__ (_) ___ ___| |_| | __ _| |__ 010 * | | | | '_ \| |/ _ \/ __| __| | / _` | '_ \ 011 * | |_| | |_) | | __/ (__| |_| |__| (_| | |_) | 012 * \___/|_.__// |\___|\___|\__|_____\__,_|_.__/ 013 * |__/ 014 * 015 * www.ObjectLab.co.uk 016 * 017 * $Id$ 018 * 019 * Copyright 2006 the original author or authors. 020 * 021 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 022 * use this file except in compliance with the License. You may obtain a copy of 023 * the License at 024 * 025 * http://www.apache.org/licenses/LICENSE-2.0 026 * 027 * Unless required by applicable law or agreed to in writing, software 028 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 029 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 030 * License for the specific language governing permissions and limitations under 031 * the License. 032 */ 033package net.objectlab.kit.datecalc.jdk8; 034 035import java.time.LocalDate; 036import java.time.Month; 037import java.time.temporal.ChronoUnit; 038import java.time.temporal.TemporalAdjusters; 039 040import net.objectlab.kit.datecalc.common.CalculatorConstants; 041import net.objectlab.kit.datecalc.common.PeriodCountBasis; 042import net.objectlab.kit.datecalc.common.PeriodCountCalculator; 043 044/** 045 * Joda <code>LocalDatePeriod</code> based implementation of the 046 * {@link net.objectlab.kit.datecalc.common.PeriodCountCalculator}. 047 * 048 * @author Benoit Xhenseval 049 * 050 */ 051public class LocalDatePeriodCountCalculator implements PeriodCountCalculator<LocalDate> { 052 053 @Override 054 public int dayDiff(final LocalDate start, final LocalDate end, final PeriodCountBasis basis) { 055 int diff; 056 057 switch (basis) { 058 case CONV_30_360: 059 diff = diffConv30v360(start, end); 060 break; 061 062 case CONV_360E_ISDA: 063 diff = diff360EIsda(start, end); 064 break; 065 066 case CONV_360E_ISMA: 067 diff = diff360EIsma(start, end); 068 break; 069 default: 070 diff = (int) ChronoUnit.DAYS.between(start, end); 071 } 072 073 return diff; 074 } 075 076 private int diff360EIsma(final LocalDate start, final LocalDate end) { 077 int dayStart = start.getDayOfMonth(); 078 int dayEnd = end.getDayOfMonth(); 079 if (dayEnd == CalculatorConstants.MONTH_31_DAYS) { 080 dayEnd = CalculatorConstants.MONTH_30_DAYS; 081 } 082 if (dayStart == CalculatorConstants.MONTH_31_DAYS) { 083 dayStart = CalculatorConstants.MONTH_30_DAYS; 084 } 085 return (end.getYear() - start.getYear()) * CalculatorConstants.YEAR_360 + (end.getMonthValue() - start.getMonthValue()) * CalculatorConstants.MONTH_30_DAYS + dayEnd - dayStart; 086 } 087 088 // See https://en.wikipedia.org/wiki/Day_count_convention#30E.2F360_ISDA 089 private int diff360EIsda(final LocalDate start, final LocalDate end) { 090 if (start.equals(end)) { 091 return 0; 092 } 093 int dayStart = start.getDayOfMonth(); 094 int dayEnd = end.getDayOfMonth(); 095 if (start.getMonth().length(start.isLeapYear()) == dayStart) { 096 dayStart = CalculatorConstants.MONTH_30_DAYS; 097 } 098 if (end.getMonth() != Month.FEBRUARY && end.getMonth().length(end.isLeapYear()) == dayEnd) { 099 dayEnd = CalculatorConstants.MONTH_30_DAYS; 100 } 101 return (end.getYear() - start.getYear()) * CalculatorConstants.YEAR_360 + (end.getMonthValue() - start.getMonthValue()) * CalculatorConstants.MONTH_30_DAYS + dayEnd - dayStart; 102 } 103 104 private int diffConv30v360(final LocalDate start, final LocalDate end) { 105 int dayStart = start.getDayOfMonth(); 106 int dayEnd = end.getDayOfMonth(); 107 if (dayEnd == CalculatorConstants.MONTH_31_DAYS && dayStart >= CalculatorConstants.MONTH_30_DAYS) { 108 dayEnd = CalculatorConstants.MONTH_30_DAYS; 109 } 110 if (dayStart == CalculatorConstants.MONTH_31_DAYS) { 111 dayStart = CalculatorConstants.MONTH_30_DAYS; 112 } 113 return (end.getYear() - start.getYear()) * CalculatorConstants.YEAR_360 + (end.getMonthValue() - start.getMonthValue()) * CalculatorConstants.MONTH_30_DAYS + dayEnd - dayStart; 114 } 115 116 // ----------------------------------------------------------------------- 117 // 118 // ObjectLab, world leaders in the design and development of bespoke 119 // applications for the securities financing markets. 120 // www.ObjectLab.co.uk 121 // 122 // ----------------------------------------------------------------------- 123 124 @Override 125 public double monthDiff(final LocalDate start, final LocalDate end, final PeriodCountBasis basis) { 126 return yearDiff(start, end, basis) * CalculatorConstants.MONTHS_IN_YEAR; 127 } 128 129 @Override 130 public double yearDiff(final LocalDate start, final LocalDate end, final PeriodCountBasis basis) { 131 double diff = 0.0; 132 133 switch (basis) { 134 case ACT_ACT: 135 final int startYear = start.getYear(); 136 final int endYear = end.getYear(); 137 if (startYear != endYear) { 138 139 final LocalDate endOfStartYear = start.with(TemporalAdjusters.lastDayOfYear()); 140 final LocalDate startOfEndYear = end.withDayOfYear(1); 141 142 final long diff1 = ChronoUnit.DAYS.between(start, endOfStartYear); 143 final long diff2 = ChronoUnit.DAYS.between(startOfEndYear, end); 144 diff = (diff1 + 1.0) / start.lengthOfYear() + (endYear - startYear - 1.0) + (double) diff2 / (double) end.lengthOfYear(); 145 } 146 break; 147 148 case CONV_30_360: 149 case CONV_360E_ISDA: 150 case CONV_360E_ISMA: 151 case ACT_360: 152 diff = dayDiff(start, end, basis) / CalculatorConstants.YEAR_360_0; 153 break; 154 155 case ACT_365: 156 diff = dayDiff(start, end, basis) / CalculatorConstants.YEAR_365_0; 157 break; 158 159 default: 160 throw new UnsupportedOperationException("Sorry ACT_UST is not supported"); 161 } 162 163 return diff; 164 } 165} 166 167/* 168 * ObjectLab, http://www.objectlab.co.uk/open is sponsoring the ObjectLab Kit. 169 * 170 * Based in London, we are world leaders in the design and development of 171 * bespoke applications for the securities financing markets. 172 * 173 * <a href="http://www.objectlab.co.uk/open">Click here to learn more about 174 * us</a> ___ _ _ _ _ _ / _ \| |__ (_) ___ ___| |_| | __ _| |__ | | | | '_ \| |/ 175 * _ \/ __| __| | / _` | '_ \ | |_| | |_) | | __/ (__| |_| |__| (_| | |_) | 176 * \___/|_.__// |\___|\___|\__|_____\__,_|_.__/ |__/ 177 * 178 * www.ObjectLab.co.uk 179 */