繁体   English   中英

推荐用于Joda-Time的DateMidnight

[英]Recommended use for Joda-Time's DateMidnight

LocalDate#toDateMidnight内容如下:

从v1.5开始,建议您避免使用DateMidnight并使用toDateTimeAtStartOfDay(),因为下面有详细说明。

如果默认时区在午夜切换到夏令时,则此方法将引发异常,此LocalDate表示该切换日期。 问题是在所需的日期没有午夜这样的时间,因此抛出了这样的例外。

在某些时区中不存在午夜这一事实似乎足以避免完全使用DateMidnight (假设您的代码没有使用已知没有此DST情况的固定时区,并且永远不需要使用不同的时区未来)。

但是,不推荐使用DateMidnight并且在DateMidnight类本身的javadoc中没有类似的建议或警告。 此外, DateMidnight构造函数很乐意接受一个即时和时区,使得在给定的一天不存在午夜,而不是抛出像LocalDate#toDateMidnight这样的IllegalArgumentException 生成的DateMidnight行为类似于DateTime并且在一天的开始时间。

当某天某天不存在午夜时,为什么LocalDate#toDateMidnight抛出异常,而DateMidnight构造函数却没有? DateMidnight的推荐用例是什么?

没有充分的理由使用DateMidnight LocalDate是更好的选择。 这是因为午夜不会在某些时区发生一次,完全搞乱了班级的可用性,并在应用程序中制造错误。

修复了构造函数以避免最严重的问题,但是看到DateMidnight对象的内部毫秒值指向01:00并不是很好。

新的DateTime()。 建议使用withTimeAtStartOfDay()

或者更好地直接使用LocalDate方法toDateTimeAtStartOfDay来绕过DateTime对象的创建(与上面的答案相关 )。

new LocalDate().toDateTimeAtStartOfDay( myDateTimeZone )

TL;博士

使用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)

java.time

由于Joda-Time项目现在处于维护模式,并且团队建议迁移到java.time类,我将使用java.time添加示例。

如果要将整个日期表示为一个整体,请使用LocalDate类。 LocalDate类表示没有时间且没有时区的仅日期值。

时区对于确定日期至关重要。 对于任何给定的时刻,日期在全球范围内因地区而异。 例如, 法国巴黎午夜过后几分钟是新的一天,而在魁北克蒙特利尔仍然是“昨天”。

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.time框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

现在处于维护模式Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310

您可以直接与数据库交换java.time对象。 使用符合JDBC 4.2或更高版本的JDBC驱动程序 不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。 您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

看看我的代码中的异常

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()来避免类似的异常。

请随意编辑我的答案谢谢

这是一个更简单的解决方案,它将检查dateTime是否发生在当地时间的午夜

private boolean isAtMidnight(org.joda.time.DateTime dateTime) {
   return dateTime.toLocalDateTime().getMillisOfDay() == 0;
}

暂无
暂无

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

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