Java: как проверить, находится ли Date в определенном диапазоне? - PullRequest
62 голосов
/ 30 января 2009

У меня есть ряд диапазонов с датами начала и окончания. Я хочу проверить, находится ли дата в этом диапазоне.

Date.before () и Date.after () кажутся немного неудобными в использовании. Что мне действительно нужно, это что-то вроде этого псевдокода:

boolean isWithinRange(Date testDate) {
    return testDate >= startDate && testDate <= endDate;
}

Не уверен, что это актуально, но даты, которые я извлекаю из базы данных, имеют временные метки.

Ответы [ 10 ]

111 голосов
/ 30 января 2009
boolean isWithinRange(Date testDate) {
   return !(testDate.before(startDate) || testDate.after(endDate));
}

Не кажется мне таким неловким. Обратите внимание, что я написал так вместо

return testDate.after(startDate) && testDate.before(endDate);

, поэтому он будет работать, даже если testDate точно равен одному из конечных случаев.

20 голосов
/ 09 февраля 2016

ТЛ; др

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*.
)

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 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 и 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 для сравнения. В работе с датой и временем мы обычно используем подход Half-Open, где начало промежутка времени составляет включительно , а окончание exclusive .

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 Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация 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 и еще .

12 голосов
/ 30 января 2009

Это правильный путь. Календари работают так же. Лучшее, что я могу вам предложить (основываясь на вашем примере), это:

boolean isWithinRange(Date testDate) {
    return testDate.getTime() >= startDate.getTime() &&
             testDate.getTime() <= endDate.getTime();
}

Date.getTime () возвращает количество миллисекунд с 01.01.1970 00:00:00 по Гринвичу и является длинным, поэтому его легко сопоставить.

9 голосов
/ 30 января 2009

Рассмотрите возможность использования Joda Time . Я люблю эту библиотеку и хочу, чтобы она заменила текущий ужасный беспорядок в существующих классах Java Date и Calendar. Это обработка даты сделана правильно.

РЕДАКТИРОВАТЬ: Это уже не 2009, и Java 8 вышел на веки. Используйте встроенные в Java 8 классы java.time, основанные на Joda Time, как упоминает Бэзил Бурк ниже. В этом случае вам понадобится класс Period, а вот учебник Oracle о том, как его использовать.

3 голосов
/ 30 января 2009

Простой способ - преобразовать даты в миллисекунды после 1 января 1970 года (используйте Date.getTime ()), а затем сравнить эти значения.

0 голосов
/ 12 июня 2018
  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;
   }
 }
0 голосов
/ 05 сентября 2017

Мне стало понятнее,

// 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

}
0 голосов
/ 25 июля 2017

вы можете использовать вот так

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
0 голосов
/ 15 января 2017

ваша логика будет работать нормально. Как вы уже упоминали, даты, которые вы получаете из базы данных, находятся в метке времени, вам просто нужно сначала преобразовать метку времени в дату, а затем использовать эту логику.

Также не забудьте проверить нулевые даты.

Здесь я делюсь немного, чтобы преобразовать метку времени в дату.

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;
    }
}
0 голосов
/ 07 июля 2016

Неважно, какая граница даты какая.

Math.abs(date1.getTime() - date2.getTime()) == 
    Math.abs(date1.getTime() - dateBetween.getTime()) + Math.abs(dateBetween.getTime() - date2.getTime());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...