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" ) );
我们可以使用isEqual
, isBefore
和isAfter
方法进行比较。 在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.Date
, Calendar
和SimpleDateFormat
。
Joda-Time项目现在处于维护模式 ,build议迁移到java.time类。
要了解更多信息,请参阅Oracle教程 。 并search堆栈溢出了很多例子和解释。 规范是JSR 310 。
从何处获取java.time类?
- Java SE 8和SE 9及更高版本
- 内置。
- 带有捆绑实现的标准Java API的一部分。
- Java 9增加了一些小function和修复。
- Java SE 6和SE 7
- 大部分的java.timefunction都被移植到了ThreeTen-Backport中的 Java 6&7中。
- Android的
- ThreeTenABP项目专门针对Android,采用了ThreeTen-Backport (上文提到)。
- 请参阅如何使用…。
ThreeTen-Extra项目将java.time扩展到其他类。 这个项目是未来可能增加java.time的一个试验场。 你可能会在这里find一些有用的类,比如Interval
, YearWeek
, YearQuarter
等等 。
这是正确的方法。 日历以相同的方式工作。 我能给你提供的最好的(根据你的例子)是这样的:
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; } }