Як відняти X днів від дати за допомогою календаря Java?


180

Хтось знає простий спосіб за допомогою календаря Java відняти X днів від дати?

Мені не вдалося знайти жодної функції, яка б дозволила мені прямо віднімати X днів від дати в Java. Чи може хтось вказати мені в правильному напрямку?


FYI, старі класи, java.util.Calendarякі зараз неспокійні, такі, як зараз, застарілі , замінені класами java.time . Дивіться Підручник від Oracle .
Василь Бурк

Відповіді:


309

Взято з документів тут :

Додає або віднімає вказану кількість часу до заданого поля календаря, виходячи з правил календаря. Наприклад, відняти 5 днів від поточного часу календаря, ви можете досягти цього, зателефонувавши:

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

1
Просто будьте обережні, роблячи це, оскільки це не завжди котиться так, як ви цього очікували.
carson

1
Ці відповіді мають багато відгуків, але чи безпечно їх використання? або це краще: stackoverflow.com/a/10796111/948268
Kuldeep Jain

44
Ви б не використовували Calendar.DAY_OF_MONTHв цьому випадку, оскільки він не буде обробляти рулон між місяцями, як хочете. Використовуйте Calendar.DAY_OF_YEARзамість цього
алгоритми

4
Це повинно бути безпечним, по- видимому , коли ви додаєте його не має значення , якщо це DAY_OF_MONTH або DAY_OF_YEAR stackoverflow.com/q/14065198/32453
rogerdpack

@carson, які проблеми з таким підходом?
tatmanblue

38

Ви можете використовувати 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. Будь-яку функцію можна легко змінити, щоб зробити її іншим способом, якщо бажаєте.


3
Не вірте .setTime та .add - це статичні методи календаря. Ви повинні використовувати змінну екземпляра c.
Едвард

@Edward: ви маєте рацію, дякую, що вказали на мою помилку, я виправив код, щоб він тепер повинен працювати належним чином.
Eli Courtwright

3
Будьте обережні з першим способом, наприклад , при роботі з leapyear днів може не спрацювати: stackoverflow.com/a/1006388/32453
rogerdpack

FYI, старі класи, java.util.Calendarякі зараз неспокійні, такі, як зараз, застарілі , замінені класами java.time . Дивіться Підручник від Oracle .
Василь Бурк

36

Відповідь Ансона буде добре працювати у простому випадку, але якщо ви збираєтесь робити якісь складніші розрахунки дати, рекомендую перевірити Joda Time . Це значно полегшить ваше життя.

FYI в Joda Time ви могли б зробити

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

1
@ShahzadImam, ознайомтеся з DateTimeFormat . Це дозволить вам перетворити екземпляри DateTime в рядки, використовуючи довільні формати. Він дуже схожий на клас java.text.DateFormat.
Майк Дек

1
Станом на Java 8, подумайте про використання java.time docs.oracle.com/javase/8/docs/api/java/time/…
toidiu

FYI, проект Joda-Time зараз перебуває в режимі обслуговування , команда радить перейти до класів java.time . Дивіться Підручник від Oracle .
Василь Бурк

19

тл; д-р

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, як сучасна, так і застаріла.


Про java.time

Java.time каркас вбудований в Java 8 і пізніших версій. Ці класи витісняти неприємні старі застарілі класи дати і часу , такі як java.util.Date, Calendar, і SimpleDateFormat.

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

Щоб дізнатися більше, дивіться навчальний посібник Oracle . І шукайте переповнення стека за багатьма прикладами та поясненнями. Специфікація - 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, і більш .


Це набагато краще вдосконалення в порівнянні з іншими варіантами (це також набагато новіше і використовує нові методи). Якщо ви зараз відвідуєте це питання, це шлях.
Shourya Bansal


5

Замість того , щоб писати мій власний , addDaysяк запропонував Елі, я вважав за краще б використовувати DateUtilsз Apache . Це зручно, особливо коли вам доведеться використовувати його у кількох місцях у своєму проекті.

API говорить:

addDays(Date date, int amount)

Додає число днів до дати повернення нового об’єкта.

Зауважте, що він повертає новий Dateоб'єкт і не вносить змін до попереднього.


2

Це легко зробити наступним чином

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());

Ця відповідь є необдуманою, використовуючи жахливі старі класи часу, які тепер є застарілими, витісненими класами java.time. Також цей код ігнорує найважливішу проблему часового поясу, наївно передбачаючи 24-годинні дні. Іншою проблемою є використання класу дати-часу для вирішення проблеми, що стосується лише дати. Використання LocalDateнабагато простіше і доцільніше.
Василь Бурк

1

Хтось рекомендував 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
}

1

Я вважаю, що за допомогою класу 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()

Також майте на увазі, що Дата не така точна, як Миттєва.


1
Або залежно від смаку, трохи коротше:Date.from(Instant.now().minus(5, ChronoUnit.DAYS))
Оле VV

1
Приємно! Ти правий. Я фактично оновив відповідь, щоб використовувати це, а також показав використання класу java.time.Duration, який у цьому випадку також є дуже потужним.
Йордан Боєв

0

Друге рішення Елі Кордрайт неправильне, воно повинно бути:

Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(Calendar.DATE, -days);
date.setTime(c.getTime().getTime());

2
Назва функції в рішенні Елі addDays: його рішення правильне. Якщо ви хочете відняти дні від дати, ви перераховуєте від’ємне значення для days.
Томас Аптон

Ну, це те, що програміст повинен вказати під час створення функції, ні? : P
користувач178973
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.