我有一系列包含开始日期和结束日期的范围。我想检查日期是否在该范围内。
Date.before()和Date.after()似乎有点尴尬。我真正需要的是这样的伪代码:
boolean isWithinRange(Date testDate) {
return testDate >= startDate && testDate <= endDate;
}
不确定是否相关,但是我从数据库中提取的日期带有时间戳。
我有一系列包含开始日期和结束日期的范围。我想检查日期是否在该范围内。
Date.before()和Date.after()似乎有点尴尬。我真正需要的是这样的伪代码:
boolean isWithinRange(Date testDate) {
return testDate >= startDate && testDate <= endDate;
}
不确定是否相关,但是我从数据库中提取的日期带有时间戳。
Answers:
boolean isWithinRange(Date testDate) {
return !(testDate.before(startDate) || testDate.after(endDate));
}
对我来说似乎并不尴尬。请注意,我是这样写的,而不是
return testDate.after(startDate) && testDate.before(endDate);
因此,即使testDate等于最终情况之一,它也可以正常工作。
date is 01-01-2014 and the range is from 01-01-2014 to 31-01-2014
如何使其有效?
date
是在清晨,然后startDate
是清晨。
Date
包含时间(小时,分钟,秒和毫秒)。因此,如果您要测试某件事是否为“今天”,则可以将Date对象设置为在0:00:00.000的时间为“ today”,而将另一个日期为0:00:00.000的“明天”。我Calendar
为此使用类,但是我敢肯定,如果您使用JodaTime或较新的基本Java类,则还有更好的方法。
ZoneId 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
是在时间轴上的一个时刻UTC纳秒的分辨率。
Instant
将您的java.util.Date
对象转换为Instant对象。
Instant start = myJUDateStart.toInstant();
Instant stop = …
如果java.sql.Timestamp
通过JDBC从数据库获取对象,请以类似的方式转换为java.time.Instant。Ajava.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
该类来定义时间跨度。该类提供了一些方法来测试间隔是否包含,邻接,封闭或重叠 其他日期时间/间隔。
本Interval
类适用于Instant
对象。该Instant
级表示时间轴上的时刻UTC,分辨率为纳秒(最多小数的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 );
该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
,和更多。
为了涵盖我的情况->我有一个范围开始和结束日期,并且日期列表可以部分地位于提供的范围内,也可以完全(重叠)。
测试涵盖的解决方案:
/**
* 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));
}
Java 8
注意:Date
不推荐使用所有(但只有一个)构造函数。Date
不推荐使用的大多数方法。参考:日期:不推荐使用的方法。除Date::from(Instant)
静态方法外,所有方法均已弃用。
因此,由于Java 8考虑使用Instant
(不可变,线程安全,leap秒感知)类型而不是Date
。REF:即时
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);
你可以这样使用
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
}
Calendar
类不是线程安全的。因此,维护一个可由多个线程访问的实例是有风险的。(B)麻烦的旧类(例如java.util.Date
和java.util.Calendar
现在是legacy),已由java.time类取代。请参阅Oracle教程。
public class TestDate {
public static void main(String[] args) {
// TODO Auto-generated method stub
String fromDate = "18-FEB-2018";
String toDate = "20-FEB-2018";
String requestDate = "19/02/2018";
System.out.println(checkBetween(requestDate,fromDate, toDate));
}
public static boolean checkBetween(String dateToCheck, String startDate, String endDate) {
boolean res = false;
SimpleDateFormat fmt1 = new SimpleDateFormat("dd-MMM-yyyy"); //22-05-2013
SimpleDateFormat fmt2 = new SimpleDateFormat("dd/MM/yyyy"); //22-05-2013
try {
Date requestDate = fmt2.parse(dateToCheck);
Date fromDate = fmt1.parse(startDate);
Date toDate = fmt1.parse(endDate);
res = requestDate.compareTo(fromDate) >= 0 && requestDate.compareTo(toDate) <=0;
}catch(ParseException pex){
pex.printStackTrace();
}
return res;
}
}
SimpleDateFormat
课程。至少不是第一选择。也并非毫无保留。今天,我们java.time
在现代Java日期和时间API及其功能方面有了很多改进DateTimeFormatter
。(2)仅代码答案很少有帮助。我们都从附带的解释中学到了东西。
您的逻辑会很好。正如您提到的,您从数据库获取的日期都在时间戳中,您只需要先将时间戳转换为日期,然后再使用此逻辑即可。
同样不要忘记检查空日期。
在这里,我分享了一些从时间戳转换为日期的信息。
公共静态日期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;
}
}