Java下个月的最后日期

时间:2019-11-27 09:03:04

标签: java date localdate

如何在Java中获取下个月的最后日期?

背景:我有一个项目,仅对订单感兴趣的用户应在下个月底之前完成。因此,我需要获取下个月的最后日期并将其与订单结束日期进行比较,如果订单结束日期小于下个月的最后日期,则意味着应选择此订单。

我的解决方案是这样的,但不确定是否是最好的解决方案:

public static boolean shouldCompleteByNextMonth(final Date endDate) {
    final LocalDate now = LocalDate.now(); // Get current local date. 
    final LocalDate nextMonth = now.plusMonths(1); // Get next month.
    final int daysInNextMonth = nextMonth.lengthOfMonth(); // Get the length of next month
    final LocalDate lastLocalDateOfNextMonth = nextMonth.plusDays(daysInNextMonth - now.getDayOfMonth());  // Get the last Date of next month

    // default time zone
    final ZoneId defaultZoneId = ZoneId.systemDefault();

    // convert last locale date to a Date
    final Date lastDateOfNextMonth = Date.from(lastLocalDateOfNextMonth.atStartOfDay(defaultZoneId).toInstant());

    // Compare with the given endDate, if last date of next month is after it, return true, else, return false.
    return lastDateOfNextMonth.after(endDate);
}

3 个答案:

答案 0 :(得分:4)

TemporalAdjusters类包含一些静态TemporalAdjuster,其中lastDayOfMonth(),因此您可以这样做

LocalDate.now()
         .plusMonth(1)
         .with(TemporalAdjusters.lastDayOfMonth());

答案 1 :(得分:2)

计算之后一个月的第一天再减去某天似乎更容易...

http://www.estesparkweather.net/archive_reports.php?date=201008

答案 2 :(得分:1)

tl; dr

YearMonth
.now( 
    ZoneId.of( "Africa/Tunis" )
)
.plusMonths( 1 ) 
.atEndOfMonth()

返回LocalDate

  

.toString():2019-12-31

但是...最好使用Half-Open方法而不是每月的最后一天。

YearMonth

YearMonth类代表整个月份。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
YearMonth nextMonth = YearMonth.now( z ).plusMonths( 1 ) ;

请注意使用时区ZoneId。在任何给定时刻,日期都会在全球范围内变化。例如,11月30日午夜过后的几分钟,在日本东京是一个新月,而在美国俄亥俄州的托莱多,它仍然是“上个月”。因此,如果在运行时当前时刻位于该月的第一天或最后一天,则需要时区才能准确确定当前月份。

在每月的最后一天询问LocalDate

LocalDate lastDayOfMonth = nextMonth.atEndOfMonth() ; 

半开放

克服时间跨度通常采用的方法是半开放式方法。开头为包含,结尾为包含

这意味着一天从一天的第一时刻开始(通常是00:00,但并非总是如此),一直持续到但不包括第二天的第一时刻。 。

在您的情况下,第一个月开始于一个月,一直持续到(但包括)下一个月的第一个月。

“半开放式”方法允许几乎没有间隙地几乎彼此邻接的时间跨度。

您的搜索条件逻辑应为查找订单,该订单的订单号等于或大于,且该订单号小于或等于次月的第一月。在Java中为>= && <

该逻辑的一种更简单形式是查找订单,其中订单日期为不早于,并且*在**为下个月的第一个月之前。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
YearMonth nextMonth = YearMonth.now( z ).plusMonths( 1 ) ;
LocalDate start = nextMonth.atDay( 1 ) ;
LocalDate stop = nextMonth.plusMonths( 1 ).atDay( 1 ) ;

LocalDateRange

ThreeTen-Extra 库添加到您的项目中,以从LocalDateRange中受益。此类将时间跨度表示为一对LocalDate对象。它提供了方便的比较方法,例如abutscontains

LocalDateRange nextMonthRange = 
    LocalDateRange.of(
        nextMonth.atDay( 1 ) ,
        nextMonth.plusMonths( 1 ).atDay( 1 )
    ) 
;

数据库

您在“问题”中提到了一个数据库。

这里是示例JDBC代码的草稿,用于查询下个月的订单。也就是说,订单到期日期为下个月之后的一个月的第一天。

请注意,我们如何在当前月份中添加两个月,以获取下个月之后的月份。

SQL的关键部分是:WHERE due_date_ < ?,用于半开查询日期,直到最近的日期为止,但,包括经过的日期(下个月之后的月份的第一天) )。

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
LocalDate firstOfMonthAfterNextMonth = YearMonth.now( z ).plusMonths( 2 ).atDay( 1 ) ;

String sql = "SELECT order_number_ FROM order_ WHERE due_date_ < ? ; " ;
try(
    Connection conn = myDataSource.getConnection() ;
    PreparedStatement ps = conn.prepareStatement( sql ) ;
)
{
    ps.setObject( 1 ; firstOfMonthAfterNextMonth ) ;
    try(
        ResultSet rs = ps.executeQuery() ;
    )
    {
        while ( rs.next() ) {
            …
        }
    }
} catch ( SQLException e ) {
    e.printStackTrace();
    … 
} catch ( SQLTimeoutException  e ) {
    e.printStackTrace();
    …
}