Как вычесть X дней из даты, используя календарь Java?

Кто-нибудь знает простой способ использовать календарь Java, чтобы вычесть X дней из даты?

Я не смог найти ни одной функции, которая позволяла бы мне напрямую вычитать X дней из даты в Java. Может ли кто-нибудь указать мне правильное направление?

11 ответов

Решение

Взято из документации здесь:

Добавляет или вычитает указанное количество времени к заданному календарному полю, основываясь на правилах календаря. Например, чтобы вычесть 5 дней из текущего времени календаря, вы можете добиться этого, позвонив:

Calendar calendar = Calendar.getInstance(); // this would default to now
calendar.add(Calendar.DAY_OF_MONTH, -5).

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

public static void addDays(Date d, int days)
{
    d.setTime( d.getTime() + (long)days*1000*60*60*24 );
}

Это получает значение метки времени даты (миллисекунды с начала эпохи) и добавляет правильное количество миллисекунд. Вы можете передать отрицательное целое число для параметра дней, чтобы сделать вычитание. Это было бы проще, чем "правильное" календарное решение:

public static void addDays(Date d, int days)
{
    Calendar c = Calendar.getInstance();
    c.setTime(d);
    c.add(Calendar.DATE, days);
    d.setTime( c.getTime().getTime() );
}

Обратите внимание, что оба эти решения меняют Date Объект передается в качестве параметра, а не возвращает совершенно новый Date, Любая функция может быть легко изменена, чтобы сделать это другим способом при желании.

Ответ Ансона подойдет для простого случая, но если вы собираетесь делать более сложные вычисления даты, я бы порекомендовал проверить Joda Time. Это сделает вашу жизнь намного проще.

К вашему сведению в Joda Time вы могли бы сделать

DateTime dt = new DateTime();
DateTime fiveDaysEarlier = dt.minusDays(5);

ТЛ; др

LocalDate.now().minusDays( 10 )

Лучше указать часовой пояс.

LocalDate.now( ZoneId.of( "America/Montreal" ) ).minusDays( 10 )

подробности

Старые классы даты и времени, связанные с ранними версиями Java, такие как java.util.Date / .Calendar, оказались хлопотными, запутанными и ошибочными. Избежать их.

java.time

Java 8 и более поздние версии вытесняют эти старые классы новой платформой java.time. Смотрите учебник. Определено JSR 310, вдохновлено Joda-Time и расширено проектом ThreeTen-Extra. Проект ThreeTen-Backport переносит классы на Java 6 и 7; проект ThreeTenABP для Android.

Вопрос неопределенный, неясно, запрашивает ли он только дату или дату-время.

LocalDate

Только для даты, без времени суток, используйте LocalDate учебный класс. Обратите внимание, что часовой пояс имеет решающее значение при определении даты, такой как "сегодня".

LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
LocalDate tenDaysAgo = today.minusDays( 10 );

ZonedDateTime

Если вы имели в виду дату и время, используйте Instant класс, чтобы получить момент на временной шкале в UTC. Оттуда установите часовой пояс, чтобы получить ZonedDateTime объект.

Instant now = Instant.now();  // UTC.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
ZonedDateTime tenDaysAgo = zdt.minusDays( 10 );

О java.time

Инфраструктура java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые классы даты и времени, такие как java.util.Date, Calendar & SimpleDateFormat,

Проект Joda-Time, находящийся сейчас в режиме обслуживания, рекомендует перейти на классы java.time.

Чтобы узнать больше, смотрите Oracle Tutorial. И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310.

Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, соответствующий JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.* классы.

Где взять классы java.time?

  • Java SE 8, Java SE 9, Java SE 10 и более поздние версии
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport.
  • Android
    • Более поздние версии Android связывают реализации классов java.time.
    • Для более ранних версий Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). Смотрите Как использовать ThreeTenABP….

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь, такие как Interval, YearWeek, YearQuarter и многое другое.

int x = -1;
Calendar cal = ...;
cal.add(Calendar.DATE, x);

редактировать: парсеру, похоже, не нравится ссылка на Javadoc, так что здесь она в текстовом виде:

http://java.sun.com/j2se/1.4.2/docs/api/java/util/Calendar.html, int)

Вместо того, чтобы писать свой собственный addDays как предположил Эли, я бы предпочел использовать DateUtils от Apache. Это удобно, особенно когда вам нужно использовать его в нескольких местах в вашем проекте.

API говорит:

addDays(Date date, int amount)

Добавляет количество дней к дате, возвращая новый объект.

Обратите внимание, что он возвращает новый Date объект и не вносит изменений в саму предыдущую.

Я столкнулся с той же проблемой, когда мне нужно было вернуться на 1 день (должен иметь возможность откатиться на один, даже если предыдущий день приходится на предыдущий год или месяцы).

Я сделал следующее, в основном вычтя по 24 часа в течение 1 дня.someDateInGregorianCalendar.add(Calendar.HOUR, -24);

В качестве альтернативы я мог бы также сделать

      GregorianCalendar cal = new GregorianCalendar();
    cal.set(Calendar.YEAR, 2021);
    cal.set(Calendar.MONTH, 0);
    cal.set(Calendar.DATE, 1);
    System.out.println("Original: " + cal.getTime());
    cal.add(Calendar.DATE, -1);
    System.out.println("After adding DATE: " + cal.getTime());

ВЫХОД:

      Original: Fri Jan 01 15:08:33 CET 2021
After adding DATE: Thu Dec 31 15:08:33 CET 2020

Я считаю, что чистый и приятный способ выполнить вычитание или сложение любой единицы времени (месяцы, дни, часы, минуты, секунды, ...) может быть достигнут с использованием класса java.time.Instant.

Пример вычитания 5 дней из текущего времени и получения результата как Дата:

new Date(Instant.now().minus(5, ChronoUnit.DAYS).toEpochMilli());

Другой пример вычитания 1 часа и прибавления 15 минут:

Date.from(Instant.now().minus(Duration.ofHours(1)).plus(Duration.ofMinutes(15)));

Если вам нужна более высокая точность, Instance измеряет до наносекунд. Способы манипулирования наносекундной частью:

minusNano()
plusNano()
getNano()

Также имейте в виду, что Date не так точен, как Instant.

Это может быть легко сделано следующим

Calendar calendar = Calendar.getInstance();
        // from current time
        long curTimeInMills = new Date().getTime();
        long timeInMills = curTimeInMills - 5 * (24*60*60*1000);    // `enter code here`subtract like 5 days
        calendar.setTimeInMillis(timeInMills);
        System.out.println(calendar.getTime());

        // from specific time like (08 05 2015)
        calendar.set(Calendar.DAY_OF_MONTH, 8);
        calendar.set(Calendar.MONTH, (5-1));
        calendar.set(Calendar.YEAR, 2015);
        timeInMills = calendar.getTimeInMillis() - 5 * (24*60*60*1000);
        calendar.setTimeInMillis(timeInMills);
        System.out.println(calendar.getTime());

Кто-то рекомендовал Joda Time так - я использую этот класс CalendarDate http://calendardate.sourceforge.net/

Это несколько конкурирующий проект с Joda Time, но гораздо более базовый только в 2 классах. Это очень удобно и отлично работает для того, что мне нужно, так как я не хотел использовать пакет больше, чем мой проект. В отличие от аналогов Java, его наименьшая единица - это день, поэтому это действительно дата (без указания миллисекунд или чего-то в этом роде). После того как вы создали дату, все, что вы делаете для вычитания, это что-то вроде myDay.addDays(-5), чтобы вернуться на 5 дней назад. Вы можете использовать его, чтобы найти день недели и тому подобное. Другой пример:

CalendarDate someDay = new CalendarDate(2011, 10, 27);
CalendarDate someLaterDay = today.addDays(77);

А также:

//print 4 previous days of the week and today
String dayLabel = "";
CalendarDate today = new CalendarDate(TimeZone.getDefault());
CalendarDateFormat cdf = new CalendarDateFormat("EEE");//day of the week like "Mon"
CalendarDate currDay = today.addDays(-4);
while(!currDay.isAfter(today)) {
    dayLabel = cdf.format(currDay);
    if (currDay.equals(today))
        dayLabel = "Today";//print "Today" instead of the weekday name
    System.out.println(dayLabel);
    currDay = currDay.addDays(1);//go to next day
}

Второе решение Эли Кортрайт неверно, оно должно быть:

Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(Calendar.DATE, -days);
date.setTime(c.getTime().getTime());
Другие вопросы по тегам