LocalDate#toDateMidnight
的javdoc内容如下:
从v1.5开始,建议您避免使用DateMidnight toDateTimeAtStartOfDay()因为异常详细 下方。
如果默认时区切换,此方法将抛出异常 到夏令时午夜时间,这个LocalDate代表 那个转换日期。问题是没有这样的时间 在所需日期的午夜,因此抛出了这样的例外。
某些时区中不存在午夜这一事实似乎足以避免完全使用DateMidnight
(假设您的代码没有使用已知没有此DST情况的固定时区,并且永远不会需要在将来使用不同的时区。)
但是,DateMidnight
未被弃用,并且DateMidnight
类本身的javadoc中没有类似的建议或警告。此外,DateMidnight
构造函数愉快地接受即时和时区,使得在给定的一天不存在午夜,而不是像IllegalArgumentException
那样抛出LocalDate#toDateMidnight
。结果DateMidnight
的行为与DateTime
的行为类似,并且在一天的开始时间。
当某一天午夜不存在时,为什么LocalDate#toDateMidnight
会抛出异常,而DateMidnight
构造函数却没有? DateMidnight
的推荐用例是什么?
答案 0 :(得分:44)
没有充分理由使用DateMidnight
。 LocalDate
是更好的选择。多数民众赞成因为午夜不会在某些时区发生一次,完全搞乱了班级的可用性,并在应用程序中造成了错误。
修复了构造函数以避免最严重的问题,但是看到一个内部毫秒值指向01:00的DateMidnight
对象并不是很好。
答案 1 :(得分:34)
建议使用新的DateTime()。withTimeAtStartOfDay()。
答案 2 :(得分:8)
或者更好地直接使用LocalDate
方法toDateTimeAtStartOfDay
来绕过DateTime
对象的创建(与answer above相关)。
new LocalDate().toDateTimeAtStartOfDay( myDateTimeZone )
答案 3 :(得分:3)
使用java.time课程,特别是LocalDate::atStartOfDay
,而不是“午夜”这个滑溜的想法。
ZoneId z = ZoneId.of( "America/Montreal" ); // A time zone.
ZonedDateTime todayStart = LocalDate.now( z ).atStartOfDay( z ); // Produces a LocalDate (a whole day without time zone), then transforms into a `ZonedDateTime` (a moment on the timeline)
由于Joda-Time项目现在处于维护模式,并且团队建议迁移到java.time类,我将使用java.time添加示例。
如果您想整天代表整天,请使用LocalDate
课程。 LocalDate
类表示没有时间且没有时区的仅限日期的值。
time zone对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因地区而异。例如,在Paris France午夜后的几分钟是新的一天,而Montréal Québec中仍然是“昨天”。
ZoneId z = ZoneId.of( “America/Montreal” );
LocalDate today = LocalDate.now( z );
正如本页所讨论的那样,试图查明当天的结束是不好的做法。首先,你有一个无限可分的问题,那一天的最后一秒。您是否解决了毫秒,微秒,纳秒或其他问题,因为所有这些都是常用的?而是使用新一天的第一个时刻。
让java.time确定当天第一时刻的挂钟时间。不要假设时间为00:00:00
,因为夏令时(DST)等异常可能意味着第一时刻是01:00:00
之类的时间。此类DST调整目前用于多个国家/地区的时区。
所以,要获得片刻,时间轴上的实际点,一天的开始时调用LocalDate::atStartOfDay
。请注意,这是方法名称的简短版本,而不是Joda-Time的withTimeAtStartOfDay
方法。在ZoneId
中指定所需/预期时区以生成ZonedDateTime
对象。
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = today.atStartOfDay( z );
那么如何表示一段时间?如果我想确定这一天的开始和结束,我如何在遵循这一建议的同时做到这一点?日期工作中常用的解决方案是半开放式方法。在此方法中,跨度的开头是包含,而结尾是独占。因此,“今天”意味着从一天的第一时刻开始并一直向前跑,但不包括第二天的第一时刻。
ZonedDateTime zdtStartToday = LocalDate.now( z ).atStartOfDay( z );
ZonedDateTime zdtStartTomorrow = zdtStartToday.plusDays( 1 );
顺便说一下,ThreeTen-Extra项目有一个方便的Interval
课程,适用于这样的时间范围。
Interval todayInterval = Interval.of(
zdtStartToday.toInstant() ,
zdtStartTomorrow.toInstant()
)
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 4 :(得分:0)
查看我的代码中的异常
Illegal instant due to time zone offset transition (daylight savings time 'gap'): 2015-03-27T00:00:00.000 (Asia/Amman)
org.joda.time.IllegalInstantException: Illegal instant due to time zone offset transition (daylight savings time 'gap'): 2015-03-27T00:00:00.000 (Asia/Amman)
现在我使用
解决了这个问题LocalDate currentDate=new LocalDate();
someMethodSetsTheDate(currentDate.toDateTimeAtStartOfDay().toDate());
而不是
someMethodSetsTheDate(new DateMidnight(date.getYear(), date.getMonthOfYear(), date.getDayOfMonth()).toDate());
现在我建议使用 的 .toDateTimeAtStartOfDay()强> 避免类似的例外。
请随意编辑我的答案谢谢
答案 5 :(得分:0)
这里有一个更简单的解决方案,它将检查dateTime是否在当地时间的午夜
private boolean isAtMidnight(org.joda.time.DateTime dateTime) {
return dateTime.toLocalDateTime().getMillisOfDay() == 0;
}