Разница часов при рассмотрении даты

Мне нужно извлечь поле даты из БД и сохранить его в ВО. Как я могу сравнить разницу часов от двух дат.

Например:
Скажем date1 = 01-SEP-17 10:00:00 а также date2 = 05-SEP-17 12:00:00, Мне нужно сравнить две даты и выполнить некоторые операции, такие как:

if(hours>10){
//do something
}
if(hours<10){
//do something else
}  

Я просто могу рассчитать разницу между часами (date2-date1) как 2, но как считать дату тоже при расчете разницы между часами?

Мой настоящий код:

Date dateA = someVO.getDate();  
long date = System.currentTimeMillis();  
SimpleDateFormat df = new SimpleDateFormat("dd-MM-YY HH:mm:ss"); 
Date date1 = new Date(date); 
Date date2 = df.parse(dateA.toString());  
long date1Hours = date1.getHours();
long date2Hours = date2.getHours();  

long dateDiff = date1Hours-date2Hours;  
if(dateDiff>10){  
//something
}  
else if(dateDiff<10){  
//something else
}  

3 ответа

Решение

Сначала вам нужно изменить шаблон, используемый в SimpleDateFormat, а также использовать java.util.Locale указать, что название месяца написано на английском языке (в противном случае используется системная локаль по умолчанию, и она не всегда будет английской).

Тогда вы получите соответствующее значение миллис каждого Date, рассчитайте разницу между ними и переведите это в часы, используя java.util.concurrent.TimeUnit:

SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yy HH:mm:ss", Locale.ENGLISH);
Date date1 = df.parse("01-SEP-17 10:00:00");
Date date2 = df.parse("05-SEP-17 12:00:00");

// get the difference in hours
long dateDiff = TimeUnit.MILLISECONDS.toHours(date2.getTime() - date1.getTime());

dateDiff будет 98,

Если вы хотите сравнить с текущей датой, просто используйте new Date(),


Проблемы летнего времени

Есть одна проблема с этим подходом. Хотя это не имеет значения для большей части года, могут быть различия из-за изменений летнего времени.

По умолчанию, SimpleDateFormat использует часовой пояс JVM по умолчанию. Если между двумя датами есть переход на летнее время (или просто изменение смещения), результат может быть другим.

Пример: в Africa/Windhoek часовой пояс, 3 сентября 2017 года, в 2 часа ночи, часы сместились на 1 час вперед, с 2 часов утра до 3 часов утра (и смещение изменилось с+01:00в+02:00). Это означает, что в этот день все местные времена между 2:00 и 2:59 AM не существуют в этом часовом поясе (как будто они "пропустили" этот час).

Итак, если часовой пояс JVM по умолчаниюAfrica/Windhoekтогда разница с использованием кода выше будет 97 часов (а не 98).

Даже если ваш часовой пояс JVM по умолчанию неAfrica/Windhoekэто все еще может произойти, в зависимости от часового пояса и даты участия. Мало того, но часовой пояс по умолчанию может быть изменен без уведомления, даже во время выполнения. Всегда лучше указать, с каким часовым поясом вы работаете, а не просто полагаться на значение по умолчанию.

Вы не можете избежать DST-эффектов (если вы не используете UTC), но, по крайней мере, вы можете выбрать часовой пояс, который вы будете использовать, вместо того, чтобы полагаться на настройки системы по умолчанию (которые могут быть изменены без предварительного уведомления).

В форматере можно установить часовой пояс, поэтому все даты будут проанализированы с учетом этого часового пояса. В приведенном ниже примере я используюEurope/London, но, конечно, вы можете выбрать тот, который лучше всего подходит для вашего случая:

// set Europe/London timezone in the SimpleDateFormat
df.setTimeZone(TimeZone.getTimeZone("Europe/London"));

Теперь все проанализированные даты будут считаться в лондонском часовом поясе (но напомните, что эффекты летнего времени все еще будут учитываться - преимущество в том, что вы знаете, какой часовой пояс вы используете, и любые изменения в настройках JVM по умолчанию не сделают ваш код внезапно начать давать разные и неожиданные результаты).

Всегда используйте имена часовых поясов IANA(всегда в формате Continent/City, лайкAmerica/Sao_Paulo или же Europe/Berlin). Избегайте использования трехбуквенных сокращений (например, CST или же PST) потому что они неоднозначны и не стандартны.

Вы можете получить список всех часовых поясов, используяTimeZone.getAvailableIDs()- тогда вы можете выбрать тот, который лучше всего подходит для вашего случая.

Если вы не хотите учитывать эффекты DST, вы можете использоватьTimeZone.getTimeZone("UTC")- потому что UTC является стандартом без изменений летнего времени.


Java новый API даты / времени

Старые занятия (Date,Calendarа такжеSimpleDateFormat) есть много проблем и проблем дизайна, и они заменяются новыми API.

Если вы используете Java 8, рассмотрите возможность использования нового API java.time. Это проще, менее прослушивается и менее подвержено ошибкам, чем старые API.

Если вы используете Java <= 7, вы можете использовать ThreeTen Backport, отличный бэкпорт для новых классов даты / времени в Java 8. А для Android есть ThreeTenABP (подробнее о том, как его использовать здесь).

Код ниже работает для обоих. Разница лишь в именах пакетов (в Java 8 java.time и в ThreeTen Backport (или Android в ThreeTenABP) является org.threeten.bp), но имена классов и методов совпадают.

Сначала вам нужно проанализировать входы (используя DateTimeFormatter) и укажите в каком часовом поясе они находятся. Поскольку даты также имеют часовой пояс, я использую ZonedDateTime, который является лучшим выбором для этого случая.

Тогда вы можете легко рассчитать разницу в часах, используя ChronoUnit, В приведенном ниже примере я также использую часовой пояс Лондона в качестве примера:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // case insensitive for month name in all caps
    .parseCaseInsensitive()
    // date/time pattern
    .appendPattern("dd-MMM-yy HH:mm:ss")
    // use English locale for month name
    .toFormatter(Locale.ENGLISH)
    // set a timezone
    .withZone(ZoneId.of("Europe/London"));
// parse the dates
ZonedDateTime z1 = ZonedDateTime.parse("01-SEP-17 10:00:00", fmt);
ZonedDateTime z2 = ZonedDateTime.parse("05-SEP-17 12:00:00", fmt);
// calculate the difference in hours
long diffHours = ChronoUnit.HOURS.between(z1, z2);

Если вы хотите использовать UTC, просто измените ZoneId в ZoneOffset.UTC постоянная. Если вы хотите сравнить с текущей датой, просто используйте:

// use the same ZoneId used in the formatter if you want to consider DST effects
ZonedDateTime.now(ZoneId.of("Europe/London"));

Конверсии в / из даты

Если вам все еще нужно работать с java.util.Dateможно конвертировать из / в новый API. В Java 8 вы можете использовать нативные методы, а в Java <= 7 ThreeTen Backport имеет org.threeten.bp.DateTimeUtils учебный класс.

Чтобы преобразовать Date в новые классы:

Date date = // java.util.Date
// convert to zoneddatetime (java 8)
ZonedDateTime z = date.toInstant().atZone(ZoneId.of("Europe/London"));
// convert to zoneddatetime (java 7 ThreeTen Backport)
ZonedDateTime z = DateTimeUtils.toInstant(date).atZone(ZoneId.of("Europe/London"));

Чтобы преобразовать ZonedDateTime вернуться к дате:

// convert to zoneddatetime (java 8)
Date date = Date.from(z.toInstant());
// convert to zoneddatetime (java 7 ThreeTen Backport)
Date date = DateTimeUtils.toDate(z.toInstant());

Достаточно просто сделать это с помощью нового API Java-Time, добавленного в Java 8:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
                        .parseCaseInsensitive()
                        .appendPattern("dd-MMM-yy HH:mm:ss")
                        .toFormatter(Locale.US);
LocalDateTime date1 = LocalDateTime.parse("01-SEP-17 10:00:00", fmt);
LocalDateTime date2 = LocalDateTime.parse("05-SEP-17 12:00:00", fmt);
long hours = ChronoUnit.HOURS.between(date1, date2);
System.out.println(hours);

Выход

98

Вы, по сути, уже получили время в миллисекундах. Вы всегда можете просто сравнить миллисекунды напрямую.

long tenHoursInMillis = 36000000;
long dateVOMillis = someVO.getDate().getTime();
long dateSysMillis = System.currentTimeMillis();
if(dateSysMillis - dateAMillis > tenHoursInMillis) {
    // do something
}
else if(dateSysMillis - dateAMillis < tenHoursInMillis) {
    // do something else
}
// do something when they're equal
Другие вопросы по тегам