使用 Java 在给定上一季度结束日期的情况下查找下一季度结束日期

Find next quarter end date given previous quarter end date using 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

您可以使用 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));

为了回答你的问题,我想你正在寻找这个:

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 这意味着你可以使用 java-time API.


获取当前季度的最后一天

有理由,要获取当前季度的结束日期,我建议使用:

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());
}

您可以使用 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

这是我找到任何日期下一季度最后一天的版本(希望更具可读性):

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);
}

tl;博士

使用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

ThreeTen-Extra 库提供 类 扩展 java.time 类 的功能内置于 Java 8及以后。其中一个 类 是 YearQuarter 代表特定年份的特定季度。这些季度按日历年定义:1 月至 3 月、4 月至 6 月、7 月至 9 月、10 月至 12 月。

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

在当前年度季度基础上增加一个季度,进入下一个季度。

java.timeThreeTen-Extra 类 使用不可变对象。因此,在添加时我们会生成一个新对象,而不是改变 ("mutate") 原始对象。

YearQuarter followingYearQuarter = yearQuarter.plusQuarters( 1 ) ;

确定该季度的最后一天。

LocalDate lastDateOfFollowingYearQuarter = followingYearQuarter.atEndOfQuarter() ;

关于java.time

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.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

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

您可以直接与数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* 类.

在哪里获取java.time类?

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.