简体   繁体   English

Java下个月的最后日期

[英]Last date of next month in Java

How to get the last date of next month in Java? 如何在Java中获取下个月的最后日期?

Background: I have project, user only interested in the orders should be completed by the end of next month. 背景:我有一个项目,仅对订单感兴趣的用户应在下个月底之前完成。 So I need to get the last date of next month and compare to the order end date, if the order end date smaller than the last date of next month, that means this order should be selected out. 因此,我需要获取下个月的最后日期并将其与订单结束日期进行比较,如果订单结束日期小于下个月的最后日期,则意味着应选择此订单。

My solution is like this, but not sure is it the best one: 我的解决方案是这样的,但不确定是最好的解决方案:

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

The TemporalAdjusters class contains some static TemporalAdjuster s, amongst them lastDayOfMonth() , so you can do TemporalAdjusters类包含一些静态TemporalAdjuster ,其中包括lastDayOfMonth() ,因此您可以执行

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

It seems easier to calculate the first day of the month after that and then substracting one day... 似乎更容易计算之后的一个月的第一天,然后减去一天。

LocalDate targetDate = LocalDate.now()
                                .withDayOfMonth(1)
                                .plusMonths(2)
                                .minusDays(1);

tl;dr tl; dr

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

Returns a LocalDate . 返回LocalDate

.toString() : 2019-12-31 .toString() :2019-12-31

But… better to use Half-Open approach rather than last day of month. 但是……最好使用半开放式方法,而不是一个月的最后一天。

YearMonth

The YearMonth class represents a month as a whole. YearMonth类代表整个月份。

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

Notice the use of time zone, ZoneId . 注意时区ZoneId For any given moment, the date varies around the globe by zone. 在任何给定时刻,日期都会在全球范围内变化。 For example, a few minutes after midnight on November 30th in Tokyo Japan is a new month, while in Toledo Ohio US it is still “last month”. 例如,11月30日午夜过后的几分钟,在日本东京是一个新月,而在美国俄亥俄州的托莱多,它仍然是“上个月”。 So if at runtime the current moment is on the first or last day of the month, the time zone is required for accuracy in determining the current month. 因此,如果在运行时当前时刻位于该月的第一天或最后一天,则需要时区才能准确确定当前月份。

Ask for a LocalDate for the last day of month. 询问一个月的最后一天的LocalDate

LocalDate lastDayOfMonth = nextMonth.atEndOfMonth() ; 

Half-Open 半开

The approach commonly taken in defying a span of time is the Half-Open approach. 克服时间跨度通常采用的方法是半开放式方法。 The beginning is inclusive while the ending is exclusive . 刚开始是包容性的 ,而结局是排他的

This means a day begins with the first moment of the day (usually 00:00, but not always), and runs up to, but does not include, the first moment of the next day. 这意味着一天从一天的第一时刻开始(通常是00:00,但并非总是如此),一直持续到(但不包括) 第二天的第一时刻。

In your case, a month begi s on the first and runs up to, but does include, the first of the next month. 在你的情况,一个月初学者S对于第一跑出来,但不包括,第一下个月

The Half-Open approach allows for spans of time that nearly abut one another without gaps. 半开放式方法可以使时间跨度几乎彼此无间隙。

Your search criteria logic should be find orders where the order is equal to or greater than the first of the month AND less than the first of the following month. 您的搜索条件逻辑应为查找顺序等于或大于该月初且小于下月初的订单。 In Java that would be >= && < . 在Java中,这将是>= && <

A simpler form of that logic is find orders where the order date is not before the first of month AND *is before** the first of following month. 该逻辑的一种更简单形式是查找订单,其中订单日期不在月份的第一个月之前,而*在**的下一个月的第一个月之前。

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

Add the ThreeTen-Extra library to your project to benefit from LocalDateRange . ThreeTen-Extra库添加到您的项目中,以从LocalDateRange受益。 This class represents a span of time as a pair of LocalDate objects. 此类将时间跨度表示为一对LocalDate对象。 It offers handy methods for comparisons such as abuts and contains . 它提供了方便的方法进行比较,例如abutscontains

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

Database 数据库

You mention a database in your Question. 您在问题中提到了一个数据库。

Here is a rough-draft of example JDBC code for querying for orders through the next month. 这是示例JDBC代码的草稿,用于查询下个月的订单。 That is, orders whose due-date is before the first day of the month after next month. 也就是说,其到期日在下个月之后的月份的第一天之前的订单。

Notice how we add two months to the current month, to get the month after next. 注意我们是如何将两个几个月内为当前月,以获得未来一个月后。

The key part of the SQL is: WHERE due_date_ < ? SQL的关键部分是: WHERE due_date_ < ? for a Half-Open query of dates running up to, but not including, the passed date (the first of month after next month). 半开查询日期,直到最近(但包括)通过日期(下个月之后的月份的第一天)。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM