我有一系列有开始日期和结束日期的范围。我想检查日期是否在该范围内。
Date.before()和Date.after()似乎有点尴尬。我真正需要的是像这样的伪代码:
boolean isWithinRange(Date testDate) {
return testDate >= startDate && testDate <= endDate;
}
不确定它是否相关,但我从数据库中提取的日期有时间戳。
答案 0 :(得分:111)
boolean isWithinRange(Date testDate) {
return !(testDate.before(startDate) || testDate.after(endDate));
}
对我来说似乎不那么尴尬。请注意,我这样写而不是
return testDate.after(startDate) && testDate.before(endDate);
所以即使testDate完全等于其中一个结束案例,它也会起作用。
答案 1 :(得分:20)
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*.
)
日期时间工作通常采用“半开”方法来定义时间跨度。开头是包含,而结尾是独占。所以从星期一开始的一周到达,但不包括,在接下来的星期一。
Java 8及更高版本内置了java.time框架。补充了旧的麻烦类,包括java.util.Date/.Calendar和SimpleDateFormat。灵感来自成功的Joda-Time图书馆。由JSR 310定义。由ThreeTen-Extra项目扩展。
Instant
将java.util.Date对象转换为Instant对象。
Instant start = myJUDateStart.toInstant();
Instant stop = …
如果通过JDBC从数据库获取java.sql.Timestamp对象,convert to 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
也许您只想使用日期,而不是时间。
LocalDate
类代表一个仅限日期的值,没有时间和没有时区。
LocalDate start = LocalDate.of( 2016 , 1 , 1 ) ;
LocalDate stop = LocalDate.of( 2016 , 1 , 23 ) ;
要获取当前日期,请指定时区。在任何特定时刻,今天的日期因时区而异。例如,巴黎的新日早些时候比蒙特利尔早了。
LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
我们可以使用isEqual
,isBefore
和isAfter
方法进行比较。在日期时间工作中,我们通常使用半开放方法,其中一段时间的开始是包含,而结尾是独占。
Boolean containsToday = ( ! today.isBefore( start ) ) && ( today.isBefore( stop ) ) ;
Interval
如果您选择将ThreeTen-Extra库添加到项目中,则可以使用Interval
类来定义时间范围。该类提供了测试间隔contains,abuts,encloses或overlaps其他日期时间/间隔的方法。
Interval
类适用于Instant
个对象。 Instant
类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(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 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和&amp; SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 2 :(得分:12)
这是正确的方法。日历的工作方式相同。我能给你的最好的(根据你的例子)是:
boolean isWithinRange(Date testDate) {
return testDate.getTime() >= startDate.getTime() &&
testDate.getTime() <= endDate.getTime();
}
Date.getTime()返回自格林威治标准时间1/1/1970 00:00:00以来的毫秒数,并且很长,因此很容易比较。
答案 3 :(得分:9)
考虑使用Joda Time。我喜欢这个库,并希望它能取代现有的Java Date和Calendar类当前可怕的混乱。这是正确的日期处理。
编辑:现在不再是2009了,Java 8已经出了很多年了。使用基于Joda Time的Java 8内置java.time类,正如Basil Bourque在下面提到的那样。在这种情况下,您将需要Period类,以及Oracle's tutorial如何使用它。答案 4 :(得分:3)
一种简单的方法是在1970年1月1日之后将日期转换为毫秒(使用Date.getTime()),然后比较这些值。
答案 5 :(得分:1)
为涵盖我的情况->我有一个范围的开始和结束日期,并且日期列表可以部分位于提供的范围内,也可以完全覆盖(重叠)。
测试涵盖的解决方案:
/**
* Check has any of quote work days in provided range.
*
* @param startDate inclusively
* @param endDate inclusively
*
* @return true if any in provided range inclusively
*/
public boolean hasAnyWorkdaysInRange(LocalDate startDate, LocalDate endDate) {
if (CollectionUtils.isEmpty(workdays)) {
return false;
}
LocalDate firstWorkDay = getFirstWorkDay().getDate();
LocalDate lastWorkDay = getLastWorkDay().getDate();
return (firstWorkDay.isBefore(endDate) || firstWorkDay.equals(endDate))
&& (lastWorkDay.isAfter(startDate) || lastWorkDay.equals(startDate));
}
答案 6 :(得分:1)
Java 8
注:不推荐使用Date
的所有构造函数,但其中一个不推荐使用。 Date
的大多数方法都已弃用。参考:Date: Deprecated Methods。除Date::from(Instant)
外,所有静态方法均已弃用。
因此,由于Java 8考虑使用Instant
(不可变,线程安全、,秒感知)类型而不是Date
。 REF:Instant
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"));
return !bigAppleTime.toLocalTime().isBefore(MARKETS_OPEN)
&& !bigAppleTime.toLocalTime().isAfter(MARKETS_CLOSE);
return bigAppleTime.toLocalTime().isAfter(MARKETS_OPEN)
&& bigAppleTime.toLocalTime().isBefore(MARKETS_CLOSE);
答案 7 :(得分:1)
如果您想与 LocalDate
进行包含性比较,请使用此代码。
LocalDate from = LocalDate.of(2021,8,1);
LocalDate to = LocalDate.of(2021,8,1);
LocalDate current = LocalDate.of(2021,8,1);
boolean isDateInRage = ( ! (current.isBefore(from.minusDays(1)) && current.isBefore(to.plusDays(1))) );
答案 8 :(得分:0)
不关心哪个日期边界是哪个。
Math.abs(date1.getTime() - date2.getTime()) ==
Math.abs(date1.getTime() - dateBetween.getTime()) + Math.abs(dateBetween.getTime() - date2.getTime());
答案 9 :(得分:0)
你可以像这样使用
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
答案 10 :(得分:0)
这对我来说更清楚,
// 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
}
答案 11 :(得分:0)
{{1}}
答案 12 :(得分:-1)
你的逻辑会正常工作。正如你所提到的,你从数据库获取的日期是时间戳,你只需要先将时间戳转换为日期然后使用这个逻辑。
也不要忘记检查空日期。
这里共享一点来从时间戳转换为日期。
public static Date convertTimeStamptoDate(String val)抛出异常{
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;
}
}