/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.basics.date; import java.time.LocalDate; import java.time.Year; /** * Date adjusters that perform useful operations on {@code LocalDate}. * <p> * This is a static utility class. * Returned objects are immutable and thread-safe. */ public final class DateAdjusters { /** * Restricted constructor. */ private DateAdjusters() { } //------------------------------------------------------------------------- /** * Obtains an instance that finds the next leap day after the input date. * <p> * The adjuster returns the next occurrence of February 29 after the input date. * * @return an adjuster that finds the next leap day */ public static DateAdjuster nextLeapDay() { return DateAdjusters::nextLeapDay; } /** * Finds the next leap day after the input date. * * @param input the input date * @return the next leap day date */ static LocalDate nextLeapDay(LocalDate input) { // already a leap day, move forward either 4 or 8 years if (input.getMonthValue() == 2 && input.getDayOfMonth() == 29) { return ensureLeapDay(input.getYear() + 4); } // handle if before February 29 in a leap year if (input.isLeapYear() && input.getMonthValue() <= 2) { return LocalDate.of(input.getYear(), 2, 29); } // handle any other date return ensureLeapDay(((input.getYear() / 4) * 4) + 4); } /** * Obtains a date adjuster that finds the next leap day on or after the input date. * <p> * If the input date is February 29, the input date is returned unaltered. * Otherwise, the adjuster returns the next occurrence of February 29 after the input date. * * @return an adjuster that finds the next leap day */ public static DateAdjuster nextOrSameLeapDay() { return DateAdjusters::nextOrSameLeapDay; } /** * Finds the next leap day on or after the input date. * <p> * If the input date is February 29, the input date is returned unaltered. * Otherwise, the adjuster returns the next occurrence of February 29 after the input date. * * @param input the input date * @return the next leap day date */ static LocalDate nextOrSameLeapDay(LocalDate input) { // already a leap day, return it if (input.getMonthValue() == 2 && input.getDayOfMonth() == 29) { return input; } // handle if before February 29 in a leap year if (input.isLeapYear() && input.getMonthValue() <= 2) { return LocalDate.of(input.getYear(), 2, 29); } // handle any other date return ensureLeapDay(((input.getYear() / 4) * 4) + 4); } // handle 2100, which is not a leap year private static LocalDate ensureLeapDay(int possibleLeapYear) { if (Year.isLeap(possibleLeapYear)) { return LocalDate.of(possibleLeapYear, 2, 29); } else { return LocalDate.of(possibleLeapYear + 4, 2, 29); } } }