Расчет даты с учетом двух дат, исключая выходные - PullRequest
4 голосов
/ 17 ноября 2011

Я использую API времени Joda в проекте Spring 3.0 для вычисления дат.Теперь у меня есть даты начала и окончания, и я хочу, чтобы между этими двумя датами были выходные, кроме субботы или воскресенья.Как мне этого добиться?

Я посмотрел этот пост Время Joda - все понедельники между двумя датами .Он предлагал некоторые указания, но все еще неясен, как исключить две даты.

Ответы [ 7 ]

12 голосов
/ 18 ноября 2011

Я полагаю, ваш вопрос, как

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

Решение :

public static void main(String[] args) {
    final LocalDate start = LocalDate.now();
    final LocalDate end = new LocalDate(2012, 1, 14);

    LocalDate weekday = start;

    if (start.getDayOfWeek() == DateTimeConstants.SATURDAY ||
            start.getDayOfWeek() == DateTimeConstants.SUNDAY) {
        weekday = weekday.plusWeeks(1).withDayOfWeek(DateTimeConstants.MONDAY);
    }

    while (weekday.isBefore(end)) {
        System.out.println(weekday);

        if (weekday.getDayOfWeek() == DateTimeConstants.FRIDAY)
            weekday = weekday.plusDays(3);
        else
            weekday = weekday.plusDays(1);
    }
}
2 голосов
/ 29 августа 2014

Я новичок здесь.Я искал решение этой проблемы, которая не использовала цикл, но не нашла подходящий алгоритм.Поэтому я решил создать это решение без использования цикла, очень эффективно и код был протестирован.

public int betweenDaysIgnoreWeekends(DateTime startDate, DateTime endDate) {
    //Um numero que representa o dia da semana para a data final, exemplo segunda=1, terça=2, quarta=3...
    int dayOfWeekEndDateNumber = Integer.valueOf(endDate.dayOfWeek()
            .getAsString());
    //Um numero que representa o dia da semana para a data inicial, exemplo segunda=1, terça=2, quarta=3...
    int dayOfWeekStartDateNumber = Integer.valueOf(startDate.dayOfWeek()
            .getAsString());
    //Se a data final for sabado ou domingo, finja ser sexta-feira
    if (dayOfWeekEndDateNumber == 6 || dayOfWeekEndDateNumber == 7) {
        int DaysToAdd = 8 - dayOfWeekEndDateNumber;
        endDate = endDate.plusDays(DaysToAdd);
        dayOfWeekEndDateNumber = Integer.valueOf(endDate.dayOfWeek()
                .getAsString());
    }

    //Se a data inicial for sabado ou domingo, finja ser segunda-feira
    if (dayOfWeekStartDateNumber == 6 || dayOfWeekStartDateNumber == 7) {
        int DaysToAdd = 8 - dayOfWeekStartDateNumber;
        startDate = startDate.plusDays(DaysToAdd);
        dayOfWeekStartDateNumber = Integer.valueOf(startDate.dayOfWeek()
                .getAsString());
    }

    //Quantos dias se passaram contando os fins de semana
    int days = Days.daysBetween(startDate, endDate).getDays();
    //Quantas semanas se passaram exatamente
    int weeks = days / 7;
    //O excesso de dias que sobrou, exemplo: 1 semana e 3 dias o excess=3 e weeks=1
    int excess = days % 7;

    //Se a data inicial for igual a data final, passou 0 dia
    if (startDate.equals(endDate)) {
        return 0;
    } else {
        //O excesso de dias passou pelo fim de semana, então deve-se retirar 2 dias
        //da quantidade final de dias
        if (excess + dayOfWeekStartDateNumber >= 6) {
            //Quantidade de semanas * 5 dias uteis + o excesso de dias - o final de semana que o excesso atravessou
            return weeks * 5 + excess - 2;
        }
        //Quantidade de semanas * 5 dias uteis + o excesso de dias
        return weeks * 5 + excess;
    }
}
1 голос
/ 22 мая 2017

Я использую логику @Josh Maag уже почти год, но недавно обнаружил, что она возвращает неправильное значение, когда endDate падает в субботу.

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

public static int getDaysBetweenIgnoreWeekends(org.joda.time.DateTime startDate, org.joda.time.DateTime endDate, boolean ignoreTimeOfDay) {

    // If the start date is equal to the closing date, spent 0 days
    if (startDate.equals(endDate))
        return 0;
    if (ignoreTimeOfDay && startDate.toLocalDate().equals(endDate.toLocalDate()))
        return 0;

    // A number that represents the day for the start date, Monday = 1 , Tuesday = 2 , Wednesday = 3 ...
    int dayOfWeekStartDateNumber = startDate.getDayOfWeek();
    int dayOfWeekEndDateNumber = endDate.getDayOfWeek();

    // If the starting date is Saturday or Sunday , pretend to be Monday
    if (dayOfWeekStartDateNumber == 6 || dayOfWeekStartDateNumber == 7) {
        int DaysToAdd = 8 - dayOfWeekStartDateNumber;
        startDate = startDate.plusDays(DaysToAdd);
        dayOfWeekStartDateNumber = Integer.valueOf(startDate.dayOfWeek().getAsString());
    }

    org.joda.time.DateTime effectiveEndDate = endDate; 

    if (dayOfWeekEndDateNumber == 6 || dayOfWeekEndDateNumber == 7) {
        effectiveEndDate = endDate.minusDays(Math.abs(5 - dayOfWeekEndDateNumber)); 
    }

    // How many days have passed counting weekends
    int days;
    if(ignoreTimeOfDay) {
        days = org.joda.time.Days.daysBetween(startDate.toLocalDate(), effectiveEndDate.toLocalDate()).getDays();
    } else {
        days = org.joda.time.Days.daysBetween(startDate, effectiveEndDate).getDays();
    }

    // How many weeks have passed
    int weeks = days / 7;
    // Excess days left. E.g. one week and three days the excess will be 3

    int excess = days % 7;

    // Excess of days spent for the weekend , then it must be removed two days
    // the final number of days
    if (excess + dayOfWeekStartDateNumber >= 6) {
        // Week count * 5 working days + excess days - the weekend that excess crossed
        return weeks * 5 + excess - 2;
    }
    // Weeks count * 5 working days + excess days
    return weeks * 5 + excess;
}

В более ранней версии - следующий фрагмент вычитал дополнительный день. Вычитание -2 независимо от того, была ли дата окончания субботы или воскресенья.

if (excess + dayOfWeekStartDateNumber >= 6) {
    // Week count * 5 working days + excess days - the weekend that excess crossed
    return weeks * 5 + excess - 2;
} 

Надеюсь, это поможет!

1 голос
/ 24 июля 2015

Чтобы улучшить то, что написал @ samir-machado-de-oliveira, вот функция, которая будет вычислять дни без выходных без использования цикла. Я не сравнивал это с версией цикла, но кажется, что это будет быстрее:

/**
 * Gets number of days between two dates. Ignoring weekends.
 * @param startDate
 * @param endDate
 * @return
 */
public static int getDaysBetweenIgnoreWeekends(DateTime startDate, DateTime endDate) {
    // If the start date is equal to the closing date, spent 0 days
    if (startDate.equals(endDate))
        return 0;

    // A number that represents the day for the start date, Monday = 1 , Tuesday = 2 , Wednesday = 3 ...
    int dayOfWeekStartDateNumber = startDate.getDayOfWeek();

    // If the starting date is Saturday or Sunday , pretend to be Monday
    if (dayOfWeekStartDateNumber == 6 || dayOfWeekStartDateNumber == 7) {
        int DaysToAdd = 8 - dayOfWeekStartDateNumber;
        startDate = startDate.plusDays(DaysToAdd);
        dayOfWeekStartDateNumber = Integer.valueOf(startDate.dayOfWeek().getAsString());
    }

    // How many days have passed counting weekends
    int days = Days.daysBetween(startDate, endDate).getDays();

    // How many weeks have passed
    int weeks = days / 7;
    // Excess days left. E.g. one week and three days the excess will be 3
    int excess = days % 7;

    // Excess of days spent for the weekend , then it must be removed two days
    // the final number of days
    if (excess + dayOfWeekStartDateNumber >= 6) {
        // Week count * 5 working days + excess days - the weekend that excess crossed
        return weeks * 5 + excess - 2;
    }
    // Weeks count * 5 working days + excess days
    return weeks * 5 + excess;
}

Кроме того, здесь есть версия, которая позволит вам игнорировать время дня, так что если дата начала в 11:00 по времени начала и время окончания следующего дня в 10:00, она будет отображаться как 1 день вместо 0 дней.

/**
 * Gets number of days between two dates. Ignoring weekends. Ignores Hours.
 * @param startDate
 * @param endDate
 * @return
 */
public static int getDaysBetweenIgnoreWeekends(DateTime startDate, DateTime endDate) {
    return getDaysBetweenIgnoreWeekends(startDate,endDate,true);
}



/**
 * Gets number of days between two dates. Ignoring weekends.
 * @param startDate
 * @param endDate
 * @param ignoreTimeOfDay
 * @return
 */
public static int getDaysBetweenIgnoreWeekends(DateTime startDate, DateTime endDate, boolean ignoreTimeOfDay) {
    // If the start date is equal to the closing date, spent 0 days
    if (startDate.equals(endDate))
        return 0;
    if (ignoreTimeOfDay && startDate.toLocalDate().equals(endDate.toLocalDate()))
        return 0;

    // A number that represents the day for the start date, Monday = 1 , Tuesday = 2 , Wednesday = 3 ...
    int dayOfWeekStartDateNumber = startDate.getDayOfWeek();

    // If the starting date is Saturday or Sunday , pretend to be Monday
    if (dayOfWeekStartDateNumber == 6 || dayOfWeekStartDateNumber == 7) {
        int DaysToAdd = 8 - dayOfWeekStartDateNumber;
        startDate = startDate.plusDays(DaysToAdd);
        dayOfWeekStartDateNumber = Integer.valueOf(startDate.dayOfWeek().getAsString());
    }

    // How many days have passed counting weekends
    int days;
    if(ignoreTimeOfDay) {
        days = Days.daysBetween(startDate.toLocalDate(), endDate.toLocalDate()).getDays();
    } else {
        days = Days.daysBetween(startDate, endDate).getDays();
    }

    // How many weeks have passed
    int weeks = days / 7;
    // Excess days left. E.g. one week and three days the excess will be 3
    int excess = days % 7;

    // Excess of days spent for the weekend , then it must be removed two days
    // the final number of days
    if (excess + dayOfWeekStartDateNumber >= 6) {
        // Week count * 5 working days + excess days - the weekend that excess crossed
        return weeks * 5 + excess - 2;
    }
    // Weeks count * 5 working days + excess days
    return weeks * 5 + excess;
}
0 голосов
/ 05 апреля 2018

Аккуратно используя потоки Java 8:

  public LocalDate[] filterWeekdaysForRange(final LocalDate start,final LocalDate end) {
    return Stream.iterate(start, date -> date.plusDays(1))
            .limit(ChronoUnit.DAYS.between(start, end)+1)
            .filter(d->d.getDayOfWeek() != SATURDAY)
            .filter(d->d.getDayOfWeek() != SUNDAY)
            .toArray(LocalDate[]::new);
  }

Это адаптация решения, представленного здесь: https://stackoverflow.com/a/38220748/744133

0 голосов
/ 06 октября 2016

Возвращает дату окончания, исключая выходные

public static Date addDaysBySkipWeekend(Date startDate, int numDays) {
        Calendar dateCal = Calendar.getInstance();
        dateCal.setTime(startDate);
        for (int i = 0; i < numDays-1; i++) {
            dateCal.add(dateCal.DATE, 1);
            if(dateCal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY 
                    || dateCal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY  ){
                dateCal.add(dateCal.DATE, 1);
                i--;
            }
        }
        return dateCal.getTime();
    }
0 голосов
/ 17 ноября 2011

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

...