Сумма двух дат в Java
Как добавить две даты в Java?
Пример: сумма "2010-01-14 19:16:17" "0000-10-03 01:10:05"
приведет к "2010-11-17 20:26:22".
Я знаю, как это сделать, используя Calendar и добавляя поле по полю.
Есть ли другой способ суммировать их все (год/месяц/день/час/минута/секунда) сразу?
Ответы
Ответ 1
Если вы используете объект Date, вы можете просто сделать:
Date d1 = ...
Date d2 = ...
long sum = d1.getTime() + d2.getTime();
Date sumDate = new Date(sum);
В коде используется метод .getTime()
, который возвращает число миллисекунд с эпохи.
Излишне говорить, что класс Date
имеет много проблем и его следует избегать, когда это возможно.
Вместо этого вы хотите суммировать другие типы?
Обновление: для Calendar
, я бы сделал следующее (на основе javadocs):
Calendar c1 = ...
Calendar c2 = ...
long sum = c1.getTimeInMillis() + c2.getTimeInMillis();
Calendar sumCalendar = (Calendar)c1.clone();
sumCalendar.setTimeInMillis(sum);
ОБНОВЛЕНО: Как сказал Стив, это работает, если в Дате, которую вы представили здесь, предполагается, что вторая дата относится к эпохе Java. Если вы хотите начать с года "0", вам нужно учесть это (путем вычитания времени вашей эпохи).
Ответ 2
Как всегда, я бы порекомендовал API даты/времени Java 8 или Joda для работы с датой/временем, поскольку они гораздо более мощные и интуитивно понятные.
Вы можете добавлять длительности и периоды в объект DateTime тривиально. Вы можете добавить минуты/секунды/месяцы одинаково легко.
Однако вы не можете добавить две даты напрямую, так как это не имеет смысла. Это убедительная иллюстрация того, почему Joda помогает - она мешает вам делать то, что вам действительно не следует делать.
Ответ 3
Не суммируйте время в миллисерах двух дат!
Date d1 = new Date();
Date d2 = new Date();
Date dTotal = new Date(d1.getTime() + d2.getTime());
System.out.println(dTotal); // Incorrect! Misses about 1970 years.
Просто клонируйте Calendar
и добавьте части datetime по одному.
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
Calendar cTotal = (Calendar) c1.clone();
cTotal.add(Calendar.YEAR, c2.get(Calendar.YEAR));
cTotal.add(Calendar.MONTH, c2.get(Calendar.MONTH) + 1); // Months are zero-based!
cTotal.add(Calendar.DATE, c2.get(Calendar.DATE));
cTotal.add(Calendar.HOUR_OF_DAY, c2.get(Calendar.HOUR_OF_DAY));
cTotal.add(Calendar.MINUTE, c2.get(Calendar.MINUTE));
cTotal.add(Calendar.SECOND, c2.get(Calendar.SECOND));
cTotal.add(Calendar.MILLISECOND, c2.get(Calendar.MILLISECOND));
System.out.println(cTotal.getTime()); // Correct!
Излишне говорить, что JodaTime умнее и чище с этим.
Ответ 4
ТЛ; др
LocalDateTime later =
LocalDateTime
.parse (
"2010-01-14 19:16:17"
.replace ( " " , "T" )
)
.plus( Period.parse ( "P10M3D" ) )
.plus( Duration.parse ( "PT1H10M5S" ) )
;
ISO 8601
Представление промежутка времени в том же формате, что и момент, создает путаницу. Пролет совсем не то же самое, что момент.
Вместо использования формата YYYY-MM-DD HH-MM-SS
течение определенного промежутка времени я предлагаю использовать стандартный формат ISO 8601 PnYnMnDTnHnMnS. В этом формате P
обозначает начало (предположительно, "Период"), а T
отделяет часть года-месяца-дня от части часов-минут-секунд.
Пример значений:
-
PT1H30M
→ Полтора часа. -
P3Y6M4DT12H30M5S
→ Три года, шесть месяцев, четыре дня, двенадцать часов, тридцать минут и пять секунд. -
P10M3DT1H10M5S
→ Ваши вопросы продолжительностью 0000-10-03 01:10:05
.
java.time
В Вопросе и других Ответах используются проблемные старые классы даты и времени, которые теперь устарели из фреймворка java.time, встроенного в Java 8 и более поздние версии. Смотрите Oracle Tutorial. Большая часть функциональности java.time была перенесена на Java 6 и 7 в ThreeTen-Backport и дополнительно адаптирована для Android в ThreeTenABP.
Классы java.time по умолчанию используют форматы ISO 8601 при разборе и генерации строк, представляющих значения даты и времени.
Вопрос не предоставляет никакой информации о часовом поясе, поэтому здесь мы используем класс LocalDateTime
. Если мы знаем смещение от UTC, мы будем использовать класс OffsetDateTime
, а если еще лучше, мы будем знать часовой пояс, мы будем использовать класс ZonedDateTime
.
Промежутки времени в java.time делятся на пару классов. Годы-месяцы-дни представлены классом Period
, а часы-минуты-секунды обрабатываются классом Duration
.
Объединяя эти времена, мы действительно можем выполнять математику даты и времени. Здесь мы добавляем промежуток времени к начальной дате и времени, чтобы получить итоговую дату и время. И мы делаем это в очень мало строк кода. Результат действительно ожидаемый Вопросом.
Мы преобразуем входные строки в канонический формат ISO 8601, заменив пробел в середине буквой T
LocalDateTime ldt = LocalDateTime.parse ( "2010-01-14 19:16:17".replace ( " " , "T" ) );
//"0000-10-03 01:10:05"
Period period = Period.parse ( "P10M3D" );
Duration duration = Duration.parse ( "PT1H10M5S" );
LocalDateTime result = ldt.plus ( period ).plus ( duration );
Сравните с результатом, ожидаемым в Вопросе.
LocalDateTime expectation = LocalDateTime.parse ( "2010-11-17 20:26:22".replace ( " " , "T" ) );
Boolean isSame = result.equals ( expectation );
Дамп на консоль.
System.out.println ( "ldt: " + ldt + " + period: " + period + " + duration: " + duration + " is result: " + result + " compared to expectation: " + expectation + " is the same: " + isSame );
ldt: 2010-01-14T19: 16: 17 + период: P10M3D + продолжительность: PT1H10M5S - результат: 2010-11-17T20: 26: 22 по сравнению с ожиданием: 2010-11-17T20: 26: 22 - то же самое: верно
Ответ 5
Вы хотите сделать getTimeInMillis()
на обоих этих Календари, чтобы у вас было два значения честности и доброты long
, которые вы можете добавить. Затем вы можете взять сумму и занести ее в новый календарь, используя этот метод Calendar setTimeInMillis()
.
Если вы хотите добавить два Calendar
, как показано выше, или два Date
, как показано в nonoop, ответ зависит от вас, конечно. Эффект подобен, он просто зависит от того, что вы хотите сделать с результатом. A Date
в основном просто хорош для хранения и/или преобразования в String для распечатки или отображения, тогда как Calendar
позволит вам играть с отдельными значениями времени, если вы этого захотите.
Как уже упоминалось, вы используете концептуальное no-no при использовании Date
или Calendar
, которые предназначены для хранения "реальных" дат и времени, например. в 20 или 21 веке, как интервалы, то есть промежутки времени. Классы в стандартной библиотеке Java не дают вам действительно полезных инструментов для этого, поэтому классы Joda были разработаны. Все классные дети в обработке даты/времени используют их; но, с другой стороны, это включает загрузку и управление сторонней библиотекой.
Ответ 6
notnoop ответ определенно правильный. Однако, если вы собираетесь делать много обработки дат, времени и интервалов, я предлагаю вам взглянуть на класс DateUtils в apache commons lang и в joda-time.
JDK7 придет с лучшей поддержкой некоторых функций, которые предоставляет joda-time. Просто сказать... это может быть связано с тем, что ваше приложение сильно использует этот материал.
Ответ 7
Вам нужно определить свой EPOCH. Эпоха Java (например, Unix) - 1 января 1970 г. /UTC. Я предполагаю, что вы думаете, что добавляете десять месяцев, 3 дня и несколько нечетных часов с 1 января 0000 года, но у вас есть смещение эпохи до 1970 года. Математика может не работать.
Используйте Календарь или Joda (как упоминалось). Если вы просто хотите добавить несколько секунд и дней (& c), не стесняйтесь добавлять указанное количество миллисекунд к вашему первому объекту даты.
Ответ 8
Используйте метод добавления класса календаря для добавления двух дат в java.
Calendar calendar=Calendar.getInstance();
calendar.add(Calendar.Date,23);
calendar.add(Calendar.Month,13);
calendar.add(Calendar.Year,15);
Используя метод add в классе Calendar, мы можем добавить день, месяц, год к существующей дате.
нажмите здесь для полной программы.
Ответ 9
Мое решение добавить время к дате:
private Date getMergedDateTime(Date p_date, Date p_time)
{
SimpleDateFormat sdfDate = new SimpleDateFormat("dd.MM.yyyy");
SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm");
Date merged = null;
try {
merged = new SimpleDateFormat("dd.MM.yyyy HH:mm").parse(sdfDate.format(p_date.getTime()) +" " + sdfTime.format(p_time.getTime()));
} catch (ParseException e) {
e.printStackTrace();
}
return merged;
}
Ответ 10
Иногда я тоже виноват в этой практике, сохраняя временной интервал в объекте даты и используя getTime(), как было предложено notnoop.
Это работает. Вопреки определенному мнению, это, безусловно, работает. Я просто игнорирую, что интервал может быть репрезентативным для непреднамеренной даты. Для меня быстрый и грязный способ добавить интервал, скажем, [6 лет, 6 месяцев, 6 дней, 6 часов, 6 минут, 6 секунд] до даты.