Home > Software design >  Date Difference Calculation in Java by excluding weekends
Date Difference Calculation in Java by excluding weekends

Time:10-07

Am very beginner and new to Java platform. I have the below 3 simple Java date difference calculation functions. I wanted to exclude weekends on the below calculations in all the 3 methods. Can anyone please help how to exclude weekends for the below dateDiff calculations?

public static String getDatesDiff(String date1, String date2) {

    String timeDiff = "";
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date d1 = null;
    Date d2 = null;

    try {
        d1 = format.parse(date1);
        d2 = format.parse(date2);
        long diff = d2.getTime() - d1.getTime();
        timeDiff = "" diff;
    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }
    return timeDiff;
}
public static String getDatesDiffAsDays(String date1, String date2) {
    String timeDiff = "";
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date d1 = null;
    Date d2 = null;

    try {
        d1 = format.parse(date1);
        d2 = format.parse(date2);
        long diff = d2.getTime() - d1.getTime();
        String days = "" (diff / (24 * 60 * 60 * 1000));
            
        timeDiff = days;
        timeDiff = timeDiff.replaceAll("-", "");
        timeDiff = timeDiff " days";
            
    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }
    return timeDiff;
}
public static String getDatesDiffAsDate(String date1, String date2) {
    String timeDiff = "";
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date d1 = null;
    Date d2 = null;

    try {
        d1 = format.parse(date1);
        d2 = format.parse(date2);
        long diff = d2.getTime() - d1.getTime();
        String days = (diff / (24 * 60 * 60 * 1000)) " days";
        String hours = (diff / (60 * 60 * 1000) % 24) "h";
        String minutes = (diff / 1000 % 60) "mts";
        String seconds = (diff / (60 * 1000) % 60) "sec";
    
        timeDiff = days;
        timeDiff = timeDiff.replaceAll("-", "");
    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }
    return timeDiff;
}

CodePudding user response:

This code is fundamentally broken. java.util.Date doesn't represent a date, it represents a timestamp. But if you're working with moments in time, you have a problem: Not all days are exactly 24 hours long. For example, daylight savings exists, making some days 25 or 23 hours. At specific moments in time in specific places on the planet, entire days were skipped, such as when a place switches which side of the international date line it is on, or when Russia was the last to switch from julian to gregorian (the famed October Revolution? Yeah that happened in november actually!)

Use LocalDate which represents an actual date, not a timestamp. Do not use Date, or SimpleDateFormat - these are outdated and mostly broken takes on dates and times. The java.time package is properly thought through.

When is 'the weekend'? In some places, friday and saturday are considered the weekend, not saturday and sunday.

If you're excluding weekends, presumably you'd also want to exclude mandated holidays. Many countries state that Jan 1st, regardless of what day that is, counts as a sunday, e.g. for the purposes of government buildings and services being open or not.

Lessons you need to take away from this:

  • Dates are incredibly complicated, and as a consequence, are a horrible idea for teaching basic principles.
  • Do not use java.util.Date, Calendar, GregorianCalendar, or SimpleDateFormat, ever. Use the stuff in java.time instead.
  • If you're writing math like this, you're probably doing it wrong - e.g. ChronoUnit.DAYS.between(date1, date2) does all that math for you.
  • You should probably just start at start date, and start looping: Check if that date counts as a working day or not (and if it is, increment a counter), then go to the next day. Keep going until the day is equal to the end date, and then return that counter. Yes, this is 'slow', but a computer will happily knock through 2 million days (that covers over 5000 years worth) in a heartbeat for you. The advantage is that you can calculate whether or not a day counts as a 'working day' (which can get incredibly complicated. For example, most mainland european countries and I think the US too mandates that easter is a public holiday. Go look up and how to know when easter is. Make some coffee first, though).
  • If you really insist on going formulaic and defining weekends as sunday and saturday, its better to separately calculate how many full weeks are between the two dates and multiply that by 5, and then add separately the half-week 'on the front of the range' and the half-week at the back. This will be fast even if you ask for a hypothetical range of a million years.
  • That is not how you handle exceptions. Add throws X if you don't want to deal with it right now, or, put throw new RuntimeException("unhandled", e); in your catch blocks. Not this, this is horrible. It logs half of the error and does blindly keeps going, with invalid state.
  • Almost all interesting questions, such as 'is this date a holiday?' are not answerable without knowing which culture/locale you're in. This includes seemingly obvious constants such as 'is saturday a weekend day?'.

CodePudding user response:

rzwitserloot has already brought up many valid points about problems in your code.

This is an example of how you could count the working days:

LocalDate startDate = ...;
LocalDate endDateExclusive = ...;
long days = startDate.datesUntil(endDateExclusive)
    .filter(date -> isWorkingDay(date))
    .count();

And, of course, you need to implement the isWorkingDay method. An example would be this:

public static boolean isWorkingDay(LocalDate date) {
    DayOfWeek dow = date.getDayOfWeek();
    return (dow != DayOfWeek.SATURDAY && dow != DayOfWeek.SUNDAY);
}
  • I used LocalDate to illustrate the example. LocalDate fits well if you are working with concepts like weekend days and holidays. However, if you want to also include the time component, then you should also take clock adjustments like DST into account; otherwise a "difference" does not make sense.

  • I assume the user to input an object representing some datetime value, not a String. The parsing of a string does not belong to this method, but should be handled elsewhere.

  • Already been said, but I repeat: don't use Date, Calendar and SimpleDateFormat. They're troublesome. Here are some reasons why.

  • Related