如何在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);
}
答案 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)
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
对象。它提供了方便的比较方法,例如abuts
和contains
。
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();
…
}