Сравнить объект Date с TimeStamp в Java
Когда я тестирую этот код:
java.util.Date date = new java.util.Date();
java.util.Date stamp = new java.sql.Timestamp(date.getTime());
assertTrue(date.equals(stamp));
assertTrue(date.compareTo(stamp) == 0);
assertTrue(stamp.compareTo(date) == 0);
assertTrue(stamp.equals(date));
Я буду ожидать истинного, истинного, истинного, ложного. Из-за этого:
В javadoc для java.sql.Timestamp указано:
Примечание. Этот тип является составной частью java.util.Date и отдельной наносекунды. Только целые секунды хранятся в компонент java.util.Date. Дробные секунды - нано - являются отдельный. Метод Timestamp.equals(Object) никогда не возвращает true, если передал значение типа java.util.Date, потому что компонент нано дата неизвестна. В результате метод Timestamp.equals(Object) не симметричный относительно java.util.Date.equals(Object) метод. Кроме того, метод hashcode использует базовый java.util.Date и поэтому не включает нано вычисление.
Из-за различий между классом Timestamp и java.util.Date, упомянутый выше, рекомендуется, чтобы код не просмотреть значения метки времени в качестве экземпляра java.util.Date. Отношение наследования между меткой времени и java.util.Date на самом деле означает наследование реализации, а не наследование типов.
Но вместо этого я получу истинное, ложное, истинное, ложное. Любые идеи?
EDIT: эта проблема возникает, когда я проверял два дата с помощью метода equals, но один из объектов Date исходил из класса Hibernate и отладки, я вижу, что объект содержит TimeStamp. Таким образом, метод equals оценивается как false, тогда я нашел это: http://mattfleming.com/node/141
Но когда я пытаюсь использовать код, я получаю разные результаты... если я не могу использовать ни равные, ни сравнивать, что я должен использовать, чтобы проверить, совпадают ли 2 Даты?!?!
Ответы
Ответ 1
Никан объяснил часть equals
, о compareTo
:
-
Timestamp
имеет метод compareTo(Date)
, который преобразует его в Timestamp
внутри
-
Date
выполняется сравнение путем downcasting (поскольку Timestamp
является его подклассом); но поскольку javadoc заявляет: "Отношение наследования между Timestamp и java.util.Date действительно означает наследование реализации, а не наследование типов"
Это, конечно, ужасная идея, на мой взгляд.
Ответ 2
Старые классы с датой и временем плохо разработаны
Проще говоря, классы java.sql.Timestamp/.Date/.Time - это взлом, плохой взлом. Как java.util.Date/.Calendar, они являются результатом плохого выбора дизайна.
Типы java.sql должны использоваться как можно короче, используются только для передачи данных в/из базы данных. Не используйте для бизнес-логики и дальнейшей работы.
java.time
Предыдущие классы времени были заменены рамкой java.time, встроенной в Java 8 и более поздних версий. Эти новые классы определяются JSR 310, вдохновленные очень успешной библиотекой Joda-Time и расширены проектом ThreeTen-Extra.
В конце концов мы должны увидеть, что драйверы JDBC обновлены для работы непосредственно с этими типами java.time. Но до этого дня нам нужно преобразовать в/из типов java.sql. Для таких преобразований вызовите новые методы, добавленные в старые классы.
An Instant
- это момент на временной шкале в UTC с разрешением наносекунды.
Instant instant = myJavaSqlTimestamp.toInstant();
Чтобы перейти в другое направление:
java.sql.Timestamp ts = java.sql.Timestamp.valueOf( instant );
Примените часовой пояс, чтобы получить время настенных часов.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
У классов java.time есть чистый, разумно выбранный класс. Поэтому вы можете использовать equals
и compareTo
, как и ожидалось. Обратите внимание, что классы со смещением-от-UTC или часовым поясом также предлагают методы isEqual
, isBefore
и isAfter
. Эти методы сравниваются, рассматривая моменты на временной шкале, их хронологический порядок. Методы equals
и compareTo
также учитывают смещение или временную зону.
Сведение к минимуму использования java.sql при максимальном использовании java.time делает проблемы вопросов спорными.
В Hibernate используйте конвертеры для java.time.
Поиск для многих других примеров и обсуждений.
Ответ 3
-
date.equals(штамп) return true AND stamp equals (date) возвращает false. REASON: дата игнорирует наносекундную часть метки времени, а остальные части оказываются равными, поэтому результат равен. Дробные секунды - nanos - являются отдельными. Метод Timestamp.equals(Object) никогда не возвращает true, когда передается значение типа java.util.Date, потому что компонент nanos даты неизвестен. Подробнее см. здесь.
- date.compareTo(stamp) == 0 возвращает false AND stamp.compareTo(date) == 0 возвращает true. ПРИЧИНА. В соответствии с этой функцией bug функция compareTo будет вести себя так, как она есть.
Ответ 4
У меня была та же проблема в тесте, где я хотел сравнить объекты java.util.Date
и java.sql.Timestamp
.
Я преобразовал их в LocalDate
, и это сработало:
import org.apache.commons.lang.ObjectUtils;
// date1 and date2 can be java.util.Date or java.sql.Timestamp
boolean datesAreEqual = ObjectUtils.equals(toLocalDate(date1), toLocalDate(date2));
где toLocalDate
:
import org.joda.time.LocalDate;
import java.util.Date;
public static void LocalDate toLocalDate(Date date)
{
return date != null ? LocalDate.fromDateFields(date) : null;
}
Ответ 5
Timestamp
Нанозначение не является числом наносекунд - это число миллисекунд с разрешением в миллисекундах (т.е. дробные секунды). Таким образом, в конструкторе Timestamp
он устанавливает время на супер, которое должно быть без миллисекунд. Поэтому Timestamp
всегда будет иметь меньшее значение для члена fastTime
(используемого в Date compareTo()
), чем соответствующий Date
(если, конечно, он не имеет дробных секунд).
Отметьте источник для отметки времени в строке 110.
Ответ 6
Попробуйте воссоздать дату объекта, используя "Строки", подобные этому
Date date = new Date();
Date stamp = Timestamp(date.getTime());
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String date1String = ft.format(date);
String date2String = ft.format(stamp);
Date date1 = ft.parse(date1String);
Date date2 = ft.parse(date2String);
assertTrue(date1.equals(date2)); // true
assertTrue(date1.compareTo(date2) == 0); //true
assertTrue(date2.compareTo(date1) == 0); //true
assertTrue(date2.equals(date1)); // true
Ответ 7
Я решил преобразовать Date и TimeStamp в объект Calendar, а затем сравнил свойства Календаря:
Calendar date = Calendar.getInstance();
date.setTimeInMillis(dateObject.getTime());
Calendar timestamp = Calendar.getInstance();
timestamp.setTimeInMillis(timestampObject.getTime());
if (effettoAppendice.get(Calendar.DAY_OF_MONTH) == timestamp.get(Calendar.DAY_OF_MONTH) &&
effettoAppendice.get(Calendar.MONTH) == timestamp.get(Calendar.MONTH) &&
effettoAppendice.get(Calendar.YEAR) == timestamp.get(Calendar.YEAR)) {
System.out.println("Date and Timestamp are the same");
} else {
System.out.println("Date and Timestamp are NOT the same");
}
Надеюсь, что это поможет.
Ответ 8
Взгляните на метод сравнения исходного кода для отметки времени:
public boolean equals(java.lang.Object ts) {
if (ts instanceof Timestamp) {
return this.equals((Timestamp)ts);
} else {
return false;
}
}
http://www.docjar.com/html/api/java/sql/Timestamp.java.html
Он будет возвращать true только тогда, когда объект сравнения является меткой времени.
Кроме того, вот исходный код Date: http://www.docjar.com/html/api/java/util/Date.java.html, и поскольку Timestamp наследует Date, он может сравнить его.
Ответ 9
К сожалению, класс Timestamp
перегружает метод equals(Object)
с помощью equals(Timestamp)
, поэтому сравнивать с отметками времени очень сложно.
В equals(Object)
javadocs говорит:
Проверяет, является ли этот объект Timestamp равный данному объекту. Эта версия метода равна добавлено для исправления неправильной подписи Timestamp.equals(отметка времени) и сохранить обратную совместимость с существующими файлами классов. Примечание. Этот метод не является симметричным относительно равных (Object) метод в базовом классе.
Мое эмпирическое правило никогда не сравнивает временные метки для равенства (что в любом случае бесполезно), но если вам нужно проверить равенство, сравните их, используя результат getTime()
(количество миллисекунд с 1 января 1970, 00:00).
Ответ 10
Небольшая заметка о наследовании реализации и наследовании типа.
"Класс объекта определяет, как реализуется объект. Напротив, тип объекта относится только к его интерфейсу. Наследование класса (наследование реализации) определяет реализацию объекта в терминах реализации другого объекта. Наследование типа описывает, когда объект может использоваться вместо другого".
Временные метки и даты имеют наследование реализации, как сказал JAVADOC.