Java: самый простой способ вычитания дат

Я создал класс с двумя полями, которые должны быть датами, start_date и date_passed. Я исследовал лучший способ в java иметь даты в формате YYYY MM DD, который позволяет легко вычитать дату и иметь возможность «составлять» дату, например, в будущем.

Пример того, что я хотел бы сделать...

library.circulate_book("Chemistry", **start date here**) //actual date or random date
library.pass_book("Chemistry", **Date Passed here**) //random date such as 5 days after start date
int days_had = Date_Passed - start_date

До сих пор я нашел множество способов форматирования дат с использованием классов Calendars и Date, но мне еще предстоит найти тот, который выглядит так, как будто он будет работать, учитывая, что большинство дат заканчиваются строками. Любые предложения/небольшие примеры приветствуются! Кроме того, любые ссылки на примеры были бы потрясающими!


person Bob    schedule 04.11.2015    source источник


Ответы (5)


tl;dr

Чтобы перейти от одной даты к другой, добавляя/вычитая количество дней.

LocalDate.now(
    ZoneId.of( "Pacific/Auckland" ) 
)
.minusDays( 5 )

Для расчета количества дней, месяцев и лет, прошедших между двумя датами.

Period.between( start , stop )

Разбор

Сначала вы должны проанализировать ваши строковые входы в объекты даты и времени. Затем вы работаете над предварительным формированием своей бизнес-логики с этими объектами.

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

В Java 8 и более поздних версиях используйте java.time структура. См. учебник.

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

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

String input = "2015 01 02";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "yyyy MM dd" );
LocalDate localDate = formatter.parse ( input , LocalDate :: from );

Текущая дата

Для определения сегодняшней даты требуется часовой пояс. В любой момент дата варьируется по всему земному шару в зависимости от зоны.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate todayTunis = LocalDate.now( z ) ;

Если вам нужен текущий часовой пояс JVM по умолчанию, вызовите ZoneId.systemDefault.

Вычитание дат

Это уже неоднократно обсуждалось на StackOveflow.com. Например, Как вычесть X дней из даты с помощью календаря Java?. Подробнее см. в других ответах, таких как этот мой и этот я для более подробной информации. Совет: «истекшее» — ключевое слово для поиска.

Вкратце, используйте Period для определения числа стандартных дней, месяцев и лет.

LocalDate weekLater = localDate.plusDays ( 7 );
Period period = Period.between ( localDate , weekLater );
Integer daysElapsed = period.getDays ();

Дамп на консоль.

System.out.println ( "localDate: " + localDate + " to " + weekLater + " in days: " + daysElapsed );

localDate: 2015-01-02 по 2015-01-09 в днях: 7

Обратите внимание на ограничение, что Period работает только с целыми днями, то есть со значениями только даты без времени дня. Это то, что нам нужно здесь для этого Вопроса, так что работа сделана. Если у вас есть значения даты и времени (объекты ZonedDateTime), используйте класс Days проекта ThreeTen-Extra. как указано в связанном вопросе/ответе выше.

person Basil Bourque    schedule 04.11.2015
comment
Отличный ответ, я просматриваю методы LocalDate и, возможно, я неправильно читаю, но есть ли метод, который возвращает только локальную дату, например 2015 04 11 на сегодня? - person Bob; 05.11.2015
comment
Может ли now() быть вычтено из дат позже в программе, такой как LocalDate localDate = formatter.parse ( input , LocalDate :: from ); - person Bob; 05.11.2015
comment
@user38254 user38254 Кажется, вы все еще застряли в объединении значений даты и времени с их строковыми представлениями. Чтобы получить сегодня, просто позвоните LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ;). Часовой пояс имеет решающее значение при определении даты (подумайте об этом!). Для строки используйте тот же модуль форматирования, что и выше: String output = today.format( formatter );. Найдите другие страницы StackOveflow по этой теме. - person Basil Bourque; 05.11.2015

Лучший способ сделать это в Java-8 – не ошибочный ответ Бэзила Бурка, а следующий подход:

String startDate = "2016 01 02";
String passedDate = "2016 02 29";

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
LocalDate date1 = LocalDate.parse(startDate, formatter);
LocalDate date2 = LocalDate.parse(passedDate, formatter);

long elapsedDays = ChronoUnit.DAYS.between(date1, date2);
System.out.println(elapsedDays); // 58 (correct)

Предлагаемое использование java.time.Period.getDays() опасно и часто неправильно, если истекшая продолжительность превышает один месяц. Весь Period равен P1M27D, поэтому этот код фактически запрашивает только частичное количество прошедших дней (есть также прошедший месяц):

System.out.println(Period.between(date1, date2).getDays()); // 27 (WRONG!!!)

Удовлетворяющее решение с использованием классов java.util.Date, GregorianCalendar и т. д. трудно найти. Вы можете использовать ответ Tacktheritrix, но должны учитывать тот факт, что расчетное количество прошедших дней может отличаться из-за суб-дневные части java.util.Date, а также ненадежен из-за игнорирования переключателей перехода на летнее время (где часы перескакивают на один час во многих частях мира).

Примечание: как минимум 8 внешних библиотек также предлагают хорошие решения вашей проблемы. Но я думаю, что ваш простой вариант использования не оправдывает встраивание дополнительной библиотеки, если вы еще не используете Java-8. Любое альтернативное решение, как считать прошедшие дни между двумя датами, было бы не проще, чем в Java-8 — только похоже. И поскольку вы приняли ответ Бэзила Бурка, связанный с Java-8, я предполагаю, что вы действительно используете Java-8, поэтому я опускаю ответ, как решить вашу проблему с другими библиотеками.

person Meno Hochschild    schedule 18.02.2016
comment
Изменения даты и времени в Java 8 должны были облегчить жизнь, но найти этот материал иногда сложно :) - person Mike; 27.11.2019

используйте java 8 date api или joda, нет необходимости в новых изобретениях.

несколько примеров можно найти здесь: http://examples.javacodegeeks.com/core-java/java-8-datetime-api-tutorial/

person Emerson Cod    schedule 04.11.2015
comment
У Джоды есть метод daysBetween, который, вероятно, подойдет для этой цели. - person Mark Sholund; 04.11.2015
comment
Что такое джода и как его получить? - person Bob; 04.11.2015
comment
нет, это на самом деле заблокировано в наших системах в школе, повезло, верно? - person Bob; 04.11.2015
comment
Чтобы сделать это реальным ответом, вместо ответа только по ссылке, пожалуйста, покажите, как сделать это с API даты java 8 и/или временем joda. - person Erwin Bolwidt; 04.11.2015
comment
Я хотя об этом - но в сети есть тысячи уже полностью квалифицированных примеров - зачем создавать еще один... - person Emerson Cod; 04.11.2015
comment
@EmersonCod, зачем создавать еще один… потому что StackOverflow.com задуман как авторитетный источник вопросов и ответов по программированию. Предполагается, что ваш ответ станет лучшим ответом Google/Bing на эту тему. Как Википедия, но узконаправленная. Если вы найдете такой же вопрос, отметьте его как дубликат. - person Basil Bourque; 05.11.2015

Вот ответ с использованием Calendar:

Calendar cal = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();

cal2.setTime(cal.getTime());
cal2.add(Calendar.DAY_OF_YEAR, 5);
System.out.println((cal2.getTimeInMillis() - cal.getTimeInMillis()) / (1000d * 60 * 60 * 24));
person Evan LaHurd    schedule 04.11.2015

Если вы застряли в более старой Java, вы можете использовать SimpleDateFormat.

    //For substraction
    long differenceInMillis = date1.getTime() - date2.getTime();

    //Date Format
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy MM dd");
    String dateAsString = dateFormat.format(date1); //To get a text representation
    Date dateParsed = dateFormat.parse(dateAsString); //To get it back as date
person liloargana    schedule 04.11.2015