Java: как проверить, находится ли дата в определенном диапазоне?
У меня есть ряд диапазонов с датами начала и датами окончания. Я хочу проверить, находится ли дата в этом диапазоне.
Date.before() и Date.after() кажутся немного неудобными в использовании. Мне действительно нужно что-то вроде этого псевдокода:
boolean isWithinRange(Date testDate) {
return testDate >= startDate && testDate <= endDate;
}
Не уверен, что это актуально, но даты, которые я вытаскиваю из базы данных, имеют временные метки.
Ответы
Ответ 1
boolean isWithinRange(Date testDate) {
return !(testDate.before(startDate) || testDate.after(endDate));
}
Мне кажется, что это неловко. Обратите внимание, что я написал это так, а не
return testDate.after(startDate) && testDate.before(endDate);
чтобы он работал, даже если testDate был точно равен одному из конечных случаев.
Ответ 2
ТЛ; др
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 todays 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*.
)
Полуоткрытый
Работа с датой времени обычно использует подход "Half-Open" для определения промежутка времени. Начало включено, в то время как окончание является эксклюзивным. Таким образом, неделя, начинающаяся в понедельник, заканчивается, но не включает следующий понедельник.
java.time
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 аналогичным образом. Java.sql.Timestamp уже в UTC, поэтому не нужно беспокоиться о часовых поясах.
Instant start = mySqlTimestamp.toInstant() ;
Instant stop = …
Получите текущий момент для сравнения.
Instant now = Instant.now();
Сравните с помощью методов isBefore, isAfter и равно.
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
для сравнения. В работе с датой мы обычно используем подход Half-Open, где начало промежутка времени включено, в то время как окончание является эксклюзивным.
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.time встроена в Java 8 и более поздние версии. Эти классы вытесняют неприятные старые устаревшие классы времени, такие как java.util.Date
, Calendar
и SimpleDateFormat
.
Проект Joda-Time, теперь в режиме обслуживания, советует перейти на классы java.time.
Чтобы узнать больше, ознакомьтесь с учебным пособием Oracle. И поиск Qaru для многих примеров и объяснений. Спецификация - JSR 310.
Где можно получить классы java.time?
- Java SE 8 и SE 9 и более поздние версии
- Встроенный.
- Часть стандартного Java API с интегрированной реализацией.
- Java 9 добавляет некоторые незначительные функции и исправления.
- Java SE 6 и SE 7
- Большая часть функциональных возможностей java.time включена обратно в Java 6 и 7 в ThreeTen-Backport.
- Android
Проект ThreeTen-Extra расширяет java.time с дополнительными классами. Этот проект является доказательством возможных будущих дополнений к java.time. Здесь вы можете найти полезные классы, такие как Interval
, YearWeek
, YearQuarter
и другие.
Ответ 3
Это правильный путь. Календари работают одинаково. Лучшее, что я мог предложить вам (на основе вашего примера), следующее:
boolean isWithinRange(Date testDate) {
return testDate.getTime() >= startDate.getTime() &&
testDate.getTime() <= endDate.getTime();
}
Date.getTime() возвращает число миллисекунд с 01.01.1970 00:00:00 по Гринвичу и является длинным, поэтому оно легко сравнимо.
Ответ 4
Попробуйте использовать Joda Time. Я люблю эту библиотеку и хочу, чтобы она заменила текущий ужасный беспорядок в существующих классах Java Date и Calendar. Это дата сделана правильно.
ОБНОВЛЕНИЕ: Это не 2009 больше, а Java 8 вышла на веки. Используйте Java 8, встроенные в классы java.time, основанные на Joda Time, как упомянуто выше Василием Бурке. В этом случае вам понадобится класс Period, а здесь учебник Oracle о том, как его использовать.
Ответ 5
Простым способом является преобразование дат в миллисекунды после 1 января 1970 года (используйте Date.getTime()), а затем сравните эти значения.
Ответ 6
Не заботьтесь о том, какая дата-граница есть.
Math.abs(date1.getTime() - date2.getTime()) ==
Math.abs(date1.getTime() - dateBetween.getTime()) + Math.abs(dateBetween.getTime() - date2.getTime());
Ответ 7
вы можете использовать это как
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
Ответ 8
Это было яснее для меня,
// 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
}
Ответ 9
Я не вижу причины для этого в java, когда вы можете сделать это с помощью простого оператора sql.
Как в этом вопросе/ответе:
Запрос Postgresql между диапазонами дат
SELECT
user_id
FROM
user_logs
WHERE
login_date >= '2014-02-01'
AND login_date < '2014-03-01'
Просто приспосабливайтесь к вашим потребностям и закончите. Что-то вроде:
SELECT
testdate
FROM
dates
WHERE
testdate BETWEEN startdate AND duedate
Ответ 10
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;
}
}
Ответ 11
Я сделал это так и работал хорошо (без библиотек):
public static boolean isDateBetween(Date myDate, Date initialDate, Date finalDate) { // Comparing dates
Calendar calInitial = setZeroHour(initialDate);
Calendar calFinal = setLastHout(finalDate);
Calendar calToday = Calendar.getInstance();
calToday.setTime(myDate);
return (calToday.getTime().getTime() >= calInitial.getTime().getTime()) &&
(calToday.getTime().getTime() <= calFinal.getTime().getTime());
}
public static Calendar setZeroHour(Date date) { // Initial date got 00:00:00 hours
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.SECOND,0);
calendar.set(Calendar.MINUTE,0);
calendar.set(Calendar.HOUR_OF_DAY,0);
return calendar;
}
public static Calendar setLastHout(Date date) { // Final date got 23:59:59 hours
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.SECOND,59);
calendar.set(Calendar.MINUTE,59);
calendar.set(Calendar.HOUR_OF_DAY,23);
return calendar;
}
Надеюсь, поможет! :)
Ответ 12
Чтобы быть в безопасности, я бы посмотрел на null:
if (testDate == null){
return true; // or false depending on your specs
}
return ( startDate == null || testDate.after(startDate) ) &&
( endDate == null || endDate.before(startDate) );
Ответ 13
ваша логика будет работать нормально. Поскольку вы упомянули, что даты получения ur из базы данных указаны в метке времени, вам просто нужно сначала преобразовать временную метку, а затем использовать эту логику.
Также не забудьте проверить нулевые даты.
здесь m разделить бит для преобразования с отметки времени до даты.
public static Date convertTimeStamptoDate (String val) throws 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;
}
}