Подтвердить что ты не робот

Добавить 30 дней до даты в java

почему, когда я добавляю 30 дней до сегодняшнего дня, я получил сегодня день - 30, и когда я добавляю 20, он добавляет

вот пример

import java.text.DateFormat;
import java.util.Date;

public class DatePlus
{

    public static void main(String[] args)
    {
        Date now = new Date();
        Date now1 = new Date();
        Date now2 = new Date();
        DateFormat currentDate = DateFormat.getDateInstance();

        Date addedDate1 = addDays(now2, 20);
        Date addedDate2 = addDays(now1, 30);
        System.out.println(currentDate.format(now));
        System.out.println(currentDate.format(addedDate1));
        System.out.println(currentDate.format(addedDate2));
    }

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

"это консоль"

Jul 30, 2012
Aug 19, 2012
Jul 10, 2012
4b9b3361

Ответ 1

Это связано с тем, что 30 * 1000 * 60 * 60 * 24 переполняет Integer.MAX_VALUE, а 20 * 1000 * 60 * 60 * 24 - нет.

Ответ 3

  • Date не привязан к календарной системе, используемой людьми. Он просто представляет момент времени. Добавление 30 дней до Date не имеет смысла, это похоже на добавление 20 к красному цвету.

  • Общий подход добавления 1000 * 60 * 60 * 24 неверен. Вы добавляете 86400 секунд, но один день не обязательно 86400 секунд. Это может быть на один час длиннее или короче из-за . Это может быть на одну секунду длиннее или короче из-за прыжковых секунд.

  • Что вам нужно сделать, это преобразовать Date в Calendar (который фактически представляет собой некоторую систему календаря, например GregorianCalendar). Затем просто добавьте дни:

    Calendar calendar = new GregorianCalendar(/* remember about timezone! */);
    calendar.setTime(date);
    calendar.add(Calendar.DATE, 30);
    date = calendar.getTime();
    
  • Используйте DateUtils.addDays() от Apache Commons Lang:

    DateUtils.add(date, 30);
    

    Это не нарушает написанное выше, оно преобразуется в Calendar под.

  • Или вообще избегайте этого ада и идите за Joda Time.

Ответ 4

days - целое число.

30 * 1000 * 60 * 60 * 24 - 2 592 000 000, больше, чем 2,147,483,647 (наибольший int на Java). У вас переполнение буфера, и ваш результат представляет собой значительно меньшее отрицательное число (проверьте его в двоичном формате, преобразуйте обратно в int как 2 дополнения)

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

 (long) days * 1000L * 60 * 60 * 24

Всегда рекомендуется использовать Календарь или, возможно, другой api (я слышал о JodaTime, но не использовал его), чтобы манипулировать датами.

Ответ 5

В ваших расчетах встречается целочисленное переполнение. Значение дней * 1000 * 60 * 60 * 24 больше максимального значения, которое разрешено для подписанного int при днях = 30, но не тогда, когда дни = 20. Когда вы увеличиваете целое число со знаком, максимально возможное значение, вместо того, чтобы увеличиваться в стоимости, знак переворачивается, и он становится отрицательным! Вот почему ваша дата идет назад - вы добавляете к ней отрицательное число.

Чтобы решить эту проблему, вы можете использовать длинный тип данных, который имеет гораздо большее максимальное значение, чем целое число, например:

long secondsToAdd = days;
secondsToAdd *= (1000*60*60*24);
d.setTime(d.getTime() + secondsToAdd);

Ответ 6

Как отмечали другие, конкретная проблема - это переполнение 32-разрядного целого числа.

Этот код также игнорирует критическую проблему часового пояса.

Большая проблема заключается в том, что вы пытаетесь выполнять собственные расчеты по дате, а не используя приличную библиотеку.

java.time

Классы java.time, встроенные в Java 8 и более поздние версии, вытесняют неприятные старые классы времени.

An Instant - момент на временной шкале в UTC с разрешением наносекунд.

Instant now = Instant.now();  

Примените часовой пояс, чтобы получить ZonedDateTime.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Теперь добавьте 30 дней. Пусть java.time обрабатывает аномалии, такие как переход на летнее время (DST).

ZonedDateTime zdtLater = zdt.plusDays( 30 );

Или, может быть, вы имели в виду месяц. Пусть java.time обрабатывает сведения о месяцах, имеющих разную длину.

ZonedDateTime zdtMonthLater = zdt.plusMonths( 1 );

См. этот вопрос для получения информации о преобразовании нового и старого типов. См. Новые методы, добавленные в старый класс, например:

java.util.Date utilDate = java.util.Date.from( zdt.toInstant() );
java.util.Calendar utilCalendar = java.util.GregorianCalendar.from( ZonedDateTime );