Сумма двух дат на Яве - PullRequest
       15

Сумма двух дат на Яве

15 голосов
/ 15 января 2010

Как я могу добавить две даты в Java?

Пример: сумма "2010-01-14 19:16:17" "0000-10-03 01:10:05"
приведет к "2010-11-17 20:26:22".

Я знаю, как это сделать, используя Календарь и добавляя поле за полем.

Есть ли другой способ суммировать их все (год / месяц / день / час / минута / секунда) за один раз?

Ответы [ 9 ]

28 голосов
/ 15 января 2010

Если вы используете объект 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", то вам необходимо учесть это (вычтя время своей эпохи).

9 голосов
/ 24 января 2010

Не суммируйте время в миллисекундах двух дат!

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 и добавляйте части даты и времени одну за другой.

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 умнее и чище с этим.

9 голосов
/ 15 января 2010

Как всегда, я бы порекомендовал Joda для работы с датой / временем, поскольку он намного более мощный и интуитивно понятный.

Вы можете добавлять длительности и периоды к объекту DateTime тривиально. Вы можете добавить минуты / секунды / месяцы одинаково легко.

Однако вы не можете добавить две даты напрямую, поскольку это не имеет смысла. Это убедительная иллюстрация того, почему Joda помогает - она ​​мешает вам делать то, чего на самом деле делать не следует.

5 голосов
/ 10 июля 2016

ТЛ; др

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 - то же самое : true

3 голосов
/ 15 января 2010

Вы хотите сделать getTimeInMillis() для обоих этих календарей, чтобы у вас было два честных значения long, которые можно сложить. Затем вы можете взять сумму и спрятать ее в новом календаре, используя метод setTimeInMillis() этого календаря.

Хотите ли вы добавить два Calendar с, как показано выше, или два Date с, как показано в ответе notnoop, конечно, решать вам. Эффект похож, он зависит только от того, что вы хотите сделать с результатом. Date в основном просто подходит для хранения и / или преобразования в строку для распечатки или отображения, тогда как Calendar позволит вам поиграть с отдельными значениями времени, если вы захотите.

Как уже упоминали другие, вы делаете некоторые концептуальные запреты на использование Date или Calendar, которые предназначены для хранения «реальных» дат и времени, например, те в 20-м или 21-м веке, как интервалы, то есть промежутки времени. Классы в стандартной библиотеке Java не дают вам действительно полезных инструментов для решения этой проблемы, поэтому классы Joda были разработаны. Все классные дети в обработке даты / времени используют их; но с другой стороны, это включает загрузку и управление сторонней библиотекой.

2 голосов
/ 15 января 2010

notnoop ответ определенно правильный. Однако, если вы собираетесь много обрабатывать даты, время и интервалы, я предлагаю вам взглянуть на класс DateUtils в apache commons lang и joda-time library.

JDK7 будет лучше поддерживать некоторые функции, предоставляемые joda-time. Просто скажу ... это может быть соображением, если ваше приложение интенсивно использует этот материал.

1 голос
/ 15 января 2010

Вы должны определить свой EPOCH. Эпоха Java (как и Unix) - 1 января 1970 года по Гринвичу / UTC. Я предполагаю, что вы думаете, что вы добавляете десять месяцев, 3 дня и несколько нечетных часов с 1 января 0000, но у вас есть смещение эпох до 1970 года. Математика может не обязательно работать.

Используйте календарь или Joda (как уже упоминалось). Если вы просто хотите добавить количество секунд и дней (& c), не стесняйтесь добавлять указанное количество миллисекунд к первому объекту даты.

0 голосов
/ 28 сентября 2013

Используйте метод add класса календаря, чтобы добавить две даты в Java.

Calendar calendar=Calendar.getInstance();

calendar.add(Calendar.Date,23);

calendar.add(Calendar.Month,13);

calendar.add(Calendar.Year,15);

Используя метод add в классе Calendar, мы можем добавить день, месяц, год к существующей дате.

нажмите здесь, чтобы завершить программу.

0 голосов
/ 15 января 2010

Иногда я тоже виновен в этой практике, сохраняя временной интервал в объекте даты и используя getTime (), как предлагает notnoop.

Это работает. Вопреки определенному мнению, это, безусловно, работает. Я просто игнорирую, что интервал может представлять непреднамеренную дату. Для меня это быстрый и грязный способ добавить интервал, скажем, [6 лет, 6 месяцев, 6 дней, 6 часов, 6 минут, 6 секунд] к дате.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...