pundit
pundit

Reputation: 772

Calculating dates given two dates excluding weekend

I am using Joda time api in a Spring 3.0 project for to calculate dates. Now I have a start and end date and I want to get everyday exept weekend or Saturday or Sunday between these two dates. How can I achieve this ?

I looked at this post Joda time - all mondays between two dates. It offered some guidance but still vague as how to exclude two dates.

Upvotes: 5

Views: 23474

Answers (7)

YoYo
YoYo

Reputation: 9415

Neatly using Java 8 Streams:

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

This is an adaption of a solution provided here: https://stackoverflow.com/a/38220748/744133

Upvotes: 1

Onkar Vaidya
Onkar Vaidya

Reputation: 138

I have been using @Josh Maag's logic for almost a year now but recently found that it returns wrong value when endDate happens to fall on a Saturday.

Here is the version I would like to share which considers to subtract days from endDate when it happens to be a Saturday or a Sunday.

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;
}

In the earlier version - following snippet was subtracting an extra day. Subtracting -2 no matter if endDate was a Saturday or Sunday.

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

Hope that helps!

Upvotes: 2

Josh Maag
Josh Maag

Reputation: 643

To improve upon what @samir-machado-de-oliveira posted, here is a function that will calculate days sans weekends without using a loop. I have not benchmarked this against the loop version, but it appears as though it would be faster:

/**
 * 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;
}

Also, here is a version that will allow you to ignore the time of the day, so that if the start date is at 11AM on the start time and the end time is the next day at 10AM it will show as 1 day instead of 0 days.

/**
 * 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;
}

Upvotes: 1

ranafeb14
ranafeb14

Reputation: 437

This will return the end date by excluding weekends

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

Upvotes: 0

I'm new here. I've been looking for a solution to this problem and that did not use loop but have not found a suitable algorithm. So I decided to create this solution does not use loop, very efficient and the code has been tested.

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;
    }
}

Upvotes: 2

lschin
lschin

Reputation: 6811

I assume your question is how to

get every day except weekend or Saturday or Sunday between two dates.

Solution :

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

Upvotes: 13

Mohit Athwani
Mohit Athwani

Reputation: 893

You can use the gregorian calendar to retrieve the day for a particular date. If the string is Saturday or Sunday you can neglect it.

Upvotes: 0

Related Questions