Date.before() 和 Date.after() 的使用似乎有点棘手。我真正需要的是类似于以下伪代码的东西:
boolean isWithinRange(Date testDate) {
return testDate >= startDate && testDate <= endDate;
}
不确定是否相关,但我从数据库中获取的日期有时间戳。
boolean isWithinRange(Date testDate) {
return !(testDate.before(startDate) || testDate.after(endDate));
}
我觉得这并不尴尬。请注意,我写成了那样而不是写成
。return testDate.after(startDate) && testDate.before(endDate);
即使 testDate 恰好等于结束日期之一,它也能正常工作。
日期为2014年1月1日,范围从2014年1月1日到2014年1月31日
。如何使其有效? - ShaheDate
包含时间(小时,分钟,秒和毫秒)。因此,如果您想测试某些内容是否为“今天”,则需要创建一个日期对象,该对象在时间0:00:00.000处为“今天”,并且在时间0:00:00.000处为“明天”。我使用 Calendar
类来实现,但是如果您使用 JodaTime 或较新的基本 Java 类,则肯定有更好的方法。 - Paul TomblinZoneId z = ZoneId.of( "America/Montreal" ); // A date only has meaning within a specific time zone. At 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 = …
java.sql.Timestamp
对象,可以类似地转换为java.time.Instant。 java.sql.Timestamp
已经处于UTC时区,所以不需要担心时区问题。Instant start = mySqlTimestamp.toInstant() ;
Instant stop = …
Instant now = Instant.now();
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
方法进行比较。在日期时间处理中,通常使用半开区间方法,其中时间跨度的开始是包含的,而结束是不包含的。请注意保留 HTML 标签。Boolean containsToday = ( ! today.isBefore( start ) ) && ( today.isBefore( stop ) ) ;
间隔
Interval
类来定义时间跨度。该类提供了测试时间间隔是否包含, 毗邻, 包括, 或者重叠其他日期时间/时间间隔的方法。
Interval
类适用于Instant
对象。Instant
类表示时间线上的一个时刻,以UTC为基准,分辨率为纳秒(最多九位小数)。
我们可以通过指定时区将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及以上版本。这些类替代了老旧的遗留日期时间类,如java.util.Date
、Calendar
和SimpleDateFormat
。
Joda-Time项目现处于维护模式,建议迁移到java.time
类。
要了解更多,请参阅Oracle教程。在Stack Overflow上搜索许多示例和解释。规范是JSR 310。
如何获取java.time
类?
java.time
功能在ThreeTen-Backport中回溯到Java 6和7。ThreeTen-Extra 项目扩展了 java.time
的额外类。该项目是可能未来添加到java.time
的一个试验场。您可能会在这里找到一些有用的类,例如 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 起经过的毫秒数,它是一个 long 类型,因此可以轻松进行比较。
Java 8
注意:除了一个构造函数之外,Date
的所有构造函数均已弃用。 大多数 Date
的方法也已弃用。 参考:Date: Deprecated Methods。 所有静态方法都已弃用,除了 Date::from(Instant)
。
因此,自 Java 8 以来,应该使用 Instant
类型(不可变、线程安全、支持闰秒),而不是 Date
。 参考: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);
一种简单的方法是将日期转换为1970年1月1日之后的毫秒数(使用Date.getTime()),然后比较这些值。
public boolean isBetween(LocalDate target, LocalDate min, LocalDate max) {
if (target == null || min == null || max == null) {
throw new IllegalArgumentException("paramettres can't be null");
}
return target.compareTo(min) >= 0 && target.compareTo(max) <= 0;
}
如果您想进行包容性比较,并与 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))) );
针对我的情况 -> 我有一个范围的开始和结束日期,以及一个日期列表,该列表可以部分或完全在提供的范围内(重叠)。
解决方案已经进行了测试:
/**
* 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));
}
这对我来说更清晰了。
// 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
}
Calendar
类不是线程安全的。因此,维护一个可能被多个线程访问的实例是有风险的。(B) 诸如 java.util.Date
和 java.util.Calendar
等麻烦的旧类现在已经成为遗留系统,被 java.time 类所取代。请参阅 Oracle 教程。 - Basil Bourque
java.util.Date
和java.util.Calendar
这样的老旧日期时间类现在已经成为遗留系统,被Java.time类所取代。请参阅Oracle的教程。 - Basil Bourque