tl;博士
如何正确获取当月的第一天?
LocalDate.now()
.with( TemporalAdjusters.firstDayOfMonth() )
或者……
LocalDate.now().withDayOfMonth( 1 )
或者……
YearMonth.now().atDay( 1 )
java.time
Java 8 及更高版本中的 java.time 框架取代了旧的 java.util.Date/.Calendar 类。旧的课程已被证明是麻烦的、令人困惑的和有缺陷的。避开他们。
java.time 框架的灵感来自高度成功的 Joda-Time 库,由 JSR 310 定义,由 ThreeTen-Extra 项目扩展,并在 Tutorial 中进行了解释。
LocalDate
对于仅日期值,没有时间,使用LocalDate 类。虽然LocalDate 没有指定时区,但我们必须指定时区才能确定日期,例如“今天”。例如,巴黎的新一天比蒙特利尔更早。
时区对于确定今天的日期至关重要。对于任何特定时刻,日期在世界各地因地区而异。省略时区意味着在确定当前日期时会自动应用 JVM 的当前时区。 JVM 中的任何代码都可以在运行时更改默认值,因此您走在流沙上。最好明确指定您想要/预期的时区,而不是隐式依赖当前默认值。
以continent/region 的格式指定proper time zone name,例如America/Montreal、Africa/Casablanca 或Pacific/Auckland。切勿使用 3-4 个字母的缩写,例如 EST 或 IST,因为它们不是真正的时区,没有标准化,甚至不是唯一的(!)。
在代码中,首先我们确定在特定时区看到的今天的日期。
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
LocalDate today = LocalDate.now ( zoneId );
然后我们将日期调整为第一天。
LocalDate firstOfCurrentMonth = today.with ( ChronoField.DAY_OF_MONTH , 1 );
或者,更简单地说:
LocalDate firstOfCurrentMonth = today.withDayOfMonth( 1 ) ;
转储到控制台。
System.out.println ( "For zoneId: " + zoneId + " today is: " + today + " and first of this month is " + firstOfCurrentMonth );
对于 zoneId:America/Montreal 今天是:2015-11-08,本月的第一天是 2015-11-01
或者,使用TemporalAdjuster。出于您的目的,您将在 TemporalAdjusters 类中找到方便的实现(注意复数 s),特别是 firstDayOfMonth。
LocalDate firstOfCurrentMonth = today.with( TemporalAdjusters.firstDayOfMonth() ) ;
ZonedDateTime
如果您需要一天中的某个时间,请记住,00:00:00.000并不总是因为夏令时 (DST) 和其他异常情况而出现在一天中的第一时刻。所以让 java.time 确定一天中第一时刻的正确时间。
ZonedDateTime zdt = firstOfCurrentMonth.atStartOfDay ( zoneId );
2015-11-01T00:00-04:00[美国/蒙特利尔]
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
从哪里获取 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。