Найти дату окончания следующего квартала по дате окончания предыдущего квартала с помощью Java

У меня дата окончания последнего квартала, пусть будет 30-09-20, требуется найти дату окончания следующего квартала, т.е. 31-12-20. Я использую приведенный ниже код, чтобы сделать то же самое, но в некоторых сценариях он дает неправильный результат. Это решение должно быть правильным для всех сторон.

String str = "30-09-20";
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yy");
Date date = format.parse(str);
Date newDate = DateUtils.addMonths(date, 3);
System.out.println(newDate);//Dec 30 - It should be 31 Dec

5 ответов

Решение

Чтобы ответить на ваш вопрос, я думаю, вы ищете это:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yy");
LocalDate end = LocalDate.parse("30-09-20", formatter)
    .plusMonths(3)                             // add three months to your date
    .with(TemporalAdjusters.lastDayOfMonth()); // with the last day of the month

Примечание: не используйте устаревшую библиотеку Date, вы отметили свой вопрос Java-8, что означает, что вы можете использовать API времени Java.


Получить последний день текущего квартала

У @deHaar есть причина, чтобы получить дату окончания текущего квартала, я бы предложил использовать:

public LocalDate lastDayFromDateQuarter(String date) {
    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yy");
    LocalDate ld = LocalDate.parse(date, formatter);
    int quarter = ld.get(IsoFields.QUARTER_OF_YEAR); // Get the Quarter, 1, 2, 3, 4
    // Then create a new date with new quarter * 3 and last day of month
    return ld.withMonth(quarter * 3).with(TemporalAdjusters.lastDayOfMonth());
}

Получить последний день следующего квартала

Чтобы получить последний день следующего квартала, вы можете просто добавить три месяца к своей дате следующим образом:

public static LocalDate lastDayFromDateQuarter(String date) {
    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yy");
    LocalDate ld = LocalDate.parse(date, formatter);
    int quarter = ld.get(IsoFields.QUARTER_OF_YEAR);
    return ld.withMonth(quarter * 3)
            .plusMonths(3)
            .with(TemporalAdjusters.lastDayOfMonth());
}

tl;dr

Use YearQuarter class from ThreeTen-Extra.

YearQuarter                                       // A class available in the ThreeTen-Extra library.
.from(                                            // Factory method rather than calling `new`. 
    LocalDate.of( 2020 , Month.SEPTEMBER , 30 )   // Returns a `LocalDate` object, represent a date-only value without a time-of-day and without a time zone.
)                                                 // Returns a `YearQuarter` object.
.plusQuarters( 1 )                                // Perform date-math, resulting in a new `YearQuarter` object (per immutable objects pattern). 
.atEndOfQuarter()                                 // Determine the date of last day of this year-quarter.
.toString()                                       // Generate text in standard ISO 8601 format.

2020-12-31

org.threeten.extra.YearQuarter

The ThreeTen-Extra library provides classes that extend the functionality of the java.time classes built into Java 8 and later. One of its classes is YearQuarter to represent a specific quarter in a specific year. The quarters are defined by calendar-year: Jan-Mar, Apr-June, July-Sept, Oct-Dec.

LocalDate localDate = LocalDate.of( 2020 , Month.SEPTEMBER , 30 ) ;
YearQuarter yearQuarter = YearQuarter.from( localDate ) ;

Move to the next quarter by adding one quarter to our current year-quarter.

The java.time and ThreeTen-Extra classes use immutable objects. So rather than alter ("mutate") the original object, when adding we produce a new object.

YearQuarter followingYearQuarter = yearQuarter.plusQuarters( 1 ) ;

Determine the last day of that quarter.

LocalDate lastDateOfFollowingYearQuarter = followingYearQuarter.atEndOfQuarter() ;

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search stackru for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Вот моя версия (надеюсь, более читаемая) поиска последнего дня следующего квартала для любой даты:

public LocalDate lastDayOfNextQuarter(LocalDate date) {
  Month firstMonthOfCurrentQuarter = date.getMonth().firstMonthOfQuarter();
  LocalDate lastMonthOfCurrentQuarter = date.with(firstMonthOfCurrentQuarter.plus(2));
  LocalDate lastMonthOfNextQuarter = lastMonthOfCurrentQuarter.plusMonths(3);
  return lastMonthOfNextQuarter.with(lastDayOfMonth());
}

И соответствующий метод тестирования:

@ParameterizedTest
@CsvSource({"2020-01-01,2020-06-30", "2020-02-01,2020-06-30", "2020-03-01,2020-06-30", "2020-04-10,2020-09-30",
  "2020-05-10,2020-09-30", "2020-06-10,2020-09-30", "2020-07-20,2020-12-31", "2020-08-20,2020-12-31",
  "2020-09-30,2020-12-31", "2020-10-30,2021-03-31", "2020-11-30,2021-03-31", "2020-12-31,2021-03-31"})
public void testLastDayOfNextQuarter(LocalDate input, LocalDate expected) {
  LocalDate result = timeUtils.lastDayOfNextQuarter(input);
  assertEquals(expected, result);
}

Вы можете легко манипулировать четвертью с помощью TemporalAdjusters. Смотри ниже:

    LocalDate localDate = LocalDate.now();
    LocalDate firstDayOfQuarter = localDate.with(IsoFields.DAY_OF_QUARTER, 1);
    System.out.println(firstDayOfQuarter);

    LocalDate lastDayOfQuarter = firstDayOfQuarter.plusMonths(2).with(TemporalAdjusters.lastDayOfMonth());
    System.out.println(lastDayOfQuarter);

    LocalDate firstDateOfNextQuarter = lastDayOfQuarter.plusDays(1);

    LocalDate lastDayOfNextQuarter = firstDateOfNextQuarter.plusMonths(2).with(TemporalAdjusters.lastDayOfMonth());
    System.out.println(lastDayOfNextQuarter);

Выход:

2020-01-01
2020-03-31
2020-06-30

Вы можете использовать экземпляр Calendar, чтобы получить последний день месяца.

String str = "30-12-20";
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yy");
Date date = format.parse(str);
Date newDate = DateUtils.addMonths(date, 3);

Calendar cal = new GregorianCalendar();
cal.setTime(newDate);

System.out.println(cal.getActualMaximum(Calendar.DAY_OF_MONTH));
Другие вопросы по тегам