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

我有一系列的开始date和结束date范围。 我想检查一下date是否在这个范围内。

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

boolean isWithinRange(Date testDate) { return testDate >= startDate && testDate <= endDate; } 

不知道是否相关,但我从数据库中提取的date有时间戳。

 boolean isWithinRange(Date testDate) { return !(testDate.before(startDate) || testDate.after(endDate)); } 

对我来说似乎并不尴尬。 请注意,我是这样写的,而不是

 return testDate.after(startDate) && testDate.before(endDate); 

所以即使testDate完全等于最终情况之一也是如此。

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*. ) 

半开

date时间的工作通常采用“半开放”的方法来定义一个时间跨度。 开始是包容性的,而结局是排他性的 。 所以一个星期一开始的一个星期星期一运行,但不包括。

java.time

Java 8及更高版本随附了内置的java.time框架。 Supplants包括java.util.Date/.Calendar和SimpleDateFormat等旧的麻烦类。 受到成功的Joda-Time图书馆的启发。 由JSR 310定义。由ThreeTen-Extra项目扩展。

Instant是UTC时间线上纳秒分辨率的时刻。

Instant

将您的java.util.Date对象转换为Instant对象。

 Instant start = myJUDateStart.toInstant(); Instant stop = … 

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

 Instant start = mySqlTimestamp.toInstant() ; Instant stop = … 

获取当前比较的时刻。

 Instant now = Instant.now(); 

使用isBefore,isAfter和equals方法进行比较。

 Boolean containsNow = ( ! now.isBefore( start ) ) && ( now.isBefore( stop ) ) ; 

LocalDate

也许你只想用date而不是时间来工作。

LocalDate类表示一个仅限date的值,没有时间和时区。

 LocalDate start = LocalDate.of( 2016 , 1 , 1 ) ; LocalDate stop = LocalDate.of( 2016 , 1 , 23 ) ; 

要获取当前date,请指定一个时区。 对于任何特定的时刻,今天的date因时区而异。 例如,巴黎之前的一个新的一天比蒙特利尔早。

 LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ); 

我们可以使用isEqualisBeforeisAfter方法进行比较。 在date时间工作中,我们通常使用半开放方法,其中时间跨度的开始是包含性的,而结尾是排他性的

 Boolean containsToday = ( ! today.isBefore( start ) ) && ( today.isBefore( stop ) ) ; 

Interval

如果您select将ThreeTen-Extra库添加到项目中,则可以使用Interval类定义一段时间。 该类提供方法来testing间隔是否包含 , 邻接 , 包围或重叠其他date时间间隔。

Interval类在Instant对象上工作。 Instant类表示UTC时间轴上的一个时刻,分辨率为纳秒 (最多九(9)位小数)。

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

 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 ); 

关于java.time

java.time框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧的遗留date时间类,如java.util.DateCalendarSimpleDateFormat

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

要了解更多信息,请参阅Oracle教程 。 并search堆栈溢出了很多例子和解释。 规范是JSR 310 。

从何处获取java.time类?

  • Java SE 8SE 9及更高版本
    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小function和修复。
  • Java SE 6SE 7
    • 大部分的java.timefunction都被移植到了ThreeTen-Backport中的 Java 6&7中。
  • Android的
    • ThreeTenABP项目专门针对Android,采用了ThreeTen-Backport (上文提到)。
    • 请参阅如何使用…。

ThreeTen-Extra项目将java.time扩展到其他类。 这个项目是未来可能增加java.time的一个试验场。 你可能会在这里find一些有用的类,比如IntervalYearWeekYearQuarter 等等 。

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

 boolean isWithinRange(Date testDate) { return testDate.getTime() >= startDate.getTime() && testDate.getTime() <= endDate.getTime(); } 

Date.getTime()返回自1970年1月1日00:00:00 GMT以来的毫秒数,并且很长,所以很容易比较。

考虑使用乔达时间 。 我喜欢这个库,并希望它会取代现有的Javadate和日历类当前可怕的混乱。 这是date处理正确的。

编辑:这不是2009年了,Java 8已经很久了。 使用基于Joda时间的java.time类中构build的Java 8,如下面的Basil Bourque提到的那样。 在这种情况下,您需要Period类,这里是Oracle的教程 ,介绍如何使用它。

一个简单的方法是将date转换为1970年1月1日之后的毫秒(使用Date.getTime()),然后比较这些值。

不pipe在哪个date边界是哪个。

 Math.abs(date1.getTime() - date2.getTime()) == Math.abs(date1.getTime() - dateBetween.getTime()) + Math.abs(dateBetween.getTime() - date2.getTime()); 

你可以这样使用

 Interval interval = new Interval(date1.getTime(),date2.getTime()); Interval interval2 = new Interval(date3.getTime(), date4.getTime()); Interval overlap = interval.overlap(interval2); boolean isOverlap = overlap == null ? false : true 

这对我来说更清楚了,

 // declare calendar outside the scope of isWithinRange() so that we initialize it only once private Calendar calendar = Calendar.getInstance(); public boolean isWithinRange(Date date, Date startDate, Date endDate) { calendar.setTime(startDate); int startDayOfYear = calendar.get(Calendar.DAY_OF_YEAR); // first day is 1, last day is 365 int startYear = calendar.get(Calendar.YEAR); calendar.setTime(endDate); int endDayOfYear = calendar.get(Calendar.DAY_OF_YEAR); int endYear = calendar.get(Calendar.YEAR); calendar.setTime(date); int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR); int year = calendar.get(Calendar.YEAR); return (year > startYear && year < endYear) // year is within the range || (year == startYear && dayOfYear >= startDayOfYear) // year is same as start year, check day as well || (year == endYear && dayOfYear < endDayOfYear); // year is same as end year, check day as well } 

为了安全,我会检查null:

 if (testDate == null){ return true; // or false depending on your specs } return ( startDate == null || testDate.after(startDate) ) && ( endDate == null || endDate.before(startDate) ); 

你的逻辑会正常工作。 正如你所提到的,从数据库获得的date是时间戳,你只需要将时间戳记转换为date,然后使用这个逻辑。

另外不要忘记检查空date。

这里m分享一下从时间戳转换到date。

公共静态dateconvertTimeStamptoDate(stringval)抛出exception{

  DateFormat df = null; Date date = null; try { df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); date = df.parse(val); // System.out.println("Date Converted.."); return date; } catch (Exception ex) { System.out.println(ex); return convertDate2(val); } finally { df = null; date = null; } }