Java:如何检查Date是否在一定范围内?

Mik*_*ler 66 java date

我有一系列有开始日期和结束日期的范围.我想检查日期是否在该范围内.

Date.before()和Date.after()似乎有点尴尬.我真正需要的是像这样的伪代码:

boolean isWithinRange(Date testDate) {
    return testDate >= startDate && testDate <= endDate;
}
Run Code Online (Sandbox Code Playgroud)

不确定它是否相关,但我从数据库中提取的日期有时间戳.

Pau*_*lin 119

boolean isWithinRange(Date testDate) {
   return !(testDate.before(startDate) || testDate.after(endDate));
}
Run Code Online (Sandbox Code Playgroud)

对我来说似乎不那么尴尬.请注意,我这样写而不是

return testDate.after(startDate) && testDate.before(endDate);
Run Code Online (Sandbox Code Playgroud)

所以即使testDate完全等于其中一个最终案例,它也会起作用.

  • 使用此代码时,以下内容无效:"日期为01-01-2014,范围为2014年1月1日至2014年1月31日",如何使其有效? (3认同)
  • @Shahe我要做的第一件事就是检查你日期的时间部分.很可能你的'date`是凌晨,`startDate`就在它之后. (3认同)
  • 这个否定或的技巧在七年后仍然很好。:) (2认同)

Bas*_*que 23

TL;博士

ZoneId z = ZoneId.of( "America/Montreal" );  // A date only has meaning within a specific time zone. For any given moment, the date varies around the globe by zone.
LocalDate ld = 
    givenJavaUtilDate.toInstant()  // Convert from legacy class `Date` to modern class `Instant` using new methods added to old classes.
                     .atZone( z )  // Adjust into the time zone in order to determine date.
                     .toLocalDate();  // Extract date-only value.

LocalDate today = LocalDate.now( z );  // Get today’s date for specific time zone.
LocalDate kwanzaaStart = today.withMonth( Month.DECEMBER ).withDayOfMonth( 26 );  // Kwanzaa starts on Boxing Day, day after Christmas.
LocalDate kwanzaaStop = kwanzaaStart.plusWeeks( 1 );  // Kwanzaa lasts one week.
Boolean isDateInKwanzaaThisYear = (
    ( ! today.isBefore( kwanzaaStart ) ) // Short way to say "is equal to or is after".
    &&
    today.isBefore( kwanzaaStop )  // Half-Open span of time, beginning inclusive, ending is *exclusive*.
)
Run Code Online (Sandbox Code Playgroud)

半开

日期时间工作通常采用"半开"方法来定义时间跨度.开头是包容性的,而结尾是独家的.所以从星期一开始的一周到达,但不包括,在接下来的星期一.

java.time

Java 8及更高版本内置了java.time框架.补充了旧的麻烦类,包括java.util.Date/.Calendar和SimpleDateFormat.灵感来自成功的Joda-Time图书馆.由JSR 310定义.由ThreeTen-Extra项目扩展.

An InstantUTC时间轴上的一个时刻,具有纳秒分辨率.

Instant

将java.util.Date对象转换为Instant对象.

Instant start = myJUDateStart.toInstant();
Instant stop = …
Run Code Online (Sandbox Code Playgroud)

如果从数据库通过JDBC获取java.sql.Timestamp对象,则以类似的方式转换为java.time.Instant.java.sql.Timestamp已经是UTC,因此无需担心时区.

Instant start = mySqlTimestamp.toInstant() ;
Instant stop = …
Run Code Online (Sandbox Code Playgroud)

获取当前时刻进行比较.

Instant now = Instant.now();
Run Code Online (Sandbox Code Playgroud)

比较使用方法isBefore,isAfter和equals.

Boolean containsNow = ( ! now.isBefore( start ) ) && ( now.isBefore( stop ) ) ;
Run Code Online (Sandbox Code Playgroud)

LocalDate

也许您只想使用日期,而不是时间.

LocalDate级表示日期,只值,没有时间的天,没有时区.

LocalDate start = LocalDate.of( 2016 , 1 , 1 ) ;
LocalDate stop = LocalDate.of( 2016 , 1 , 23 ) ;
Run Code Online (Sandbox Code Playgroud)

要获取当前日期,请指定时区.在任何特定时刻,今天的日期因时区而异.例如,巴黎的新日早些时候比蒙特利尔早.

LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
Run Code Online (Sandbox Code Playgroud)

我们可以使用isEqual,isBeforeisAfter方法比较.在日期时间工作中,我们通常使用半开放方法,其中一段时间​​的开始是包容性的,而结尾是排他性的.

Boolean containsToday = ( ! today.isBefore( start ) ) && ( today.isBefore( stop ) ) ;
Run Code Online (Sandbox Code Playgroud)

Interval

如果您选择将ThreeTen-Extra库添加到项目中,则可以使用Interval该类来定义时间跨度.该类提供了测试间隔是否包含,邻接,封闭重叠 其他日期时间/间隔的方法.

Interval类适用于Instant对象.该Instant级表示时间轴上的时刻UTC,分辨率为纳秒(最多9个(9)小数的位数).

我们可以LocalDate通过指定时区来调整特定时刻,即当天的第一时刻ZonedDateTime.从那里我们可以通过提取一个回到UTC Instant.

ZoneId z = ZoneId.of( "America/Montreal" );
Interval interval = 
    Interval.of( 
        start.atStartOfDay( z ).toInstant() , 
        stop.atStartOfDay( z ).toInstant() );
Instant now = Instant.now();
Boolean containsNow = interval.contains( now );
Run Code Online (Sandbox Code Playgroud)

关于java.time

java.time框架是建立在Java 8和更高版本.这些类取代麻烦的老传统日期时间类,如java.util.Date,Calendar,和SimpleDateFormat.

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

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

从哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类Interval,YearWeek,YearQuarter,和更多.


MBC*_*ook 12

这是正确的方法.日历的工作方式相同.我能给你的最好的(根据你的例子)是这样的:

boolean isWithinRange(Date testDate) {
    return testDate.getTime() >= startDate.getTime() &&
             testDate.getTime() <= endDate.getTime();
}
Run Code Online (Sandbox Code Playgroud)

Date.getTime()返回自格林尼治标准时间1/1/1970 00:00:00以来的毫秒数,并且很长,因此很容易比较.


Ben*_*rdy 9

考虑使用Joda Time.我喜欢这个库,并希望它能取代现有的Java Date和Calendar类当前可怕的混乱.这是正确的日期处理.

编辑:现在不再是2009了,Java 8已经出了很多年了.使用基于Joda Time的Java 8内置java.time类,正如Basil Bourque在下面提到的那样.在这种情况下,您将需要Period类,以及Oracle的如何使用它的教程.

  • 让我们不要忘记StackOverflow规则#46:如果有人在Java中提及日期或时间,那么有人建议切换到Joda Time.不相信我?尝试找到一个没有的问题. (22认同)
  • 难道你不相信将Joda Time引入项目是否随着时间的推移如果所有人想要做的是如提问者所说的做一个简单的比较? - (3认同)
  • 我认为你的意思是矫枉过正.在大多数图书馆添加的情况下,我会同意你的看法.然而Joda Time非常轻松,并且由于其表示的不变性,可以帮助您编写更正确的日期处理代码,因此在我看来引入它并不是一件坏事. (3认同)
  • 甚至Sun/Oracle放弃了与最早版本的Java捆绑在一起的旧日期时间类,同意用[java.time]取代旧类(http://docs.oracle.com/javase/8/docs) /api/java/time/package-summary.html)框架(受Joda-Time启发).那些旧课程的设计很差,并且被证明是麻烦和混乱的. (2认同)
  • @PaulTomblin ;-) 规则 #46 已更新。如今,有人必须提及并推荐 [java.time,现代 Java 日期和时间 API](https://docs.oracle.com/javase/tutorial/datetime/)。这个答案也已更新。 (2认同)

epo*_*pox 9

自从Java 8

注意:除了一个之外,所有Date的构造函数均已弃用。的大多数Date方法已被弃用。参考:日期:已弃用的方法。全部,但是Date::from(Instant)静态方法均已弃用。

因此,从 java 8 开始考虑使用Instant (不可变、线程安全、闰秒感知)类型而不是Date. 参考:即时

  static final LocalTime MARKETS_OPEN = LocalTime.of(07, 00);
  static final LocalTime MARKETS_CLOSE = LocalTime.of(20, 00);

    // Instant utcTime = testDate.toInstant();
    var bigAppleTime = ZonedDateTime.ofInstant(utcTime, ZoneId.of("America/New_York"));
Run Code Online (Sandbox Code Playgroud)

在包含范围内:

    return !bigAppleTime.toLocalTime().isBefore(MARKETS_OPEN)
        && !bigAppleTime.toLocalTime().isAfter(MARKETS_CLOSE);
Run Code Online (Sandbox Code Playgroud)

在独家范围内:

    return bigAppleTime.toLocalTime().isAfter(MARKETS_OPEN)
        && bigAppleTime.toLocalTime().isBefore(MARKETS_CLOSE);
Run Code Online (Sandbox Code Playgroud)