2

Hello i am having issue trying to calculate the amount of hours in a 24 hour day that took place between two different timestamps in java not including weekends.

String timestamp = rs.getString("timestamp");

 String timeStamp = new SimpleDateFormat("yyyyMMddHH").format(new Date());

   int currentTimeStamp = Integer.parseInt(timeStamp);

   String orderTime = timestamp.replace("-", "");
   String[] splitTimestamp = orderTime.split(" ");

   String finalTimestamp = splitTimestamp[0] +    splitTimestamp[1].substring(0,2);

   int orderTimeStamp = Integer.parseInt(finalTimestamp);

This currently does work but it includes weekends.

If anyone could help me out I would be very grateful.

This is all done Eastern time zone. Holidays aren't required or needed just weekends.

user1863457
  • 131
  • 2
  • 11
  • 1
    by weekends you mean only saturdays and sundays or also public holidays? And please remember about timezone issues. – Alex Salauyou Mar 21 '16 at 18:06
  • Then the task is not so trivial, because holidays are different in different countries :) – Alex Salauyou Mar 21 '16 at 18:07
  • 1
    This is all done in Eastern time usa. Don't include holidays. – user1863457 Mar 21 '16 at 18:08
  • You want the number of hours, using a 24-hour day, but exclude weekends? That seems .... weird. Usually, if you exclude weekends, you're after "working hours", not 24-hour days. – Andreas Mar 21 '16 at 18:13
  • 1
    I want 24 hour days. It is for an ordering system. – user1863457 Mar 21 '16 at 18:14
  • 1
    Maybe this helps http://stackoverflow.com/questions/4600034/calculate-number-of-weekdays-between-two-dates-in-java – RubioRic Mar 21 '16 at 18:15
  • 1
    So, since you're in eastern US timezone and exclude weekends, Daylight Savings Time is not an issue. Assuming neither start nor end date is on a weekend, simply calculate the total number of hours between them, then figure out how many weekends are between them and subtract `48*weekendCount` from the total. Using the Java 8 [`LocalDateTime`](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html) may help. – Andreas Mar 21 '16 at 18:16
  • still having issues. =( – user1863457 Mar 21 '16 at 18:30
  • Do you need actual hours? Or do you want generic days where we assume every day is exactly 24-hours long? – Basil Bourque Mar 21 '16 at 20:30

3 Answers3

4

Avoid old date-time classes

The old date-time classes bundled with the earliest versions of Java are poorly designed, confusing, and troublesome. Avoid java.util.Date/.Calendar and so on.

java.time

Use the java.time framework built into Java 8 and later. Or its backport for Java 7 & 6. See Oracle Tutorial.

I have not tried running this code; just off the top of my head. Never run, never tested. Might give you a start.

The Question seems to say that we want to assume generic 24-hour days rather than actual days (which can vary in length due to anomalies such as Daylight Saving Time). In the case of generic days, we do not care about time zone. We can use the LocalDateTime class.

If the start happens to be on a weekend, move it to the first moment of the following Monday.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyyMMddHH" );
LocalDateTime start = LocalDateTime.parse( "2016010123" , formatter );
// If on a weekend, move to first moment of Monday.
if( start.getDayOfWeek().equals( DayOfWeek.SATURDAY ) {
    start = start.plusDays( 2 ).toLocalDate().atStartOfDay(); 
}
if( start.getDayOfWeek().equals( DayOfWeek.SUNDAY ) {
    start = start.plusDays( 1 ).toLocalDate().atStartOfDay(); 
}

Ditto for the stop. If on weekend, move to first moment of the following Monday.

LocalDateTime stop = LocalDateTime.parse( "2016010723" , formatter );
// If on a weekend, move to first moment of Monday.
if( stop.getDayOfWeek().equals( DayOfWeek.SATURDAY ) {
    stop = stop.plusDays( 2 ).toLocalDate().atStartOfDay(); 
}
if( stop.getDayOfWeek().equals( DayOfWeek.SUNDAY ) {
    stop = stop.plusDays( 1 ).toLocalDate().atStartOfDay(); 
}

If the start is the same as stop, we are done: report zero.

if( start.isEqual( stop ) ) {
    return 0;
}

If the start is after the stop, we have an error condition. Throw an exception, try to correct the problem, or report zero, whatever makes sense in your app.

if( start.isAfter( stop ) ) {
    return 0; // Or consider it a problem, throw exception.
}

Let's divide this problem into three parts:

  • First partial day,
  • Last partial day,
  • Number of whole days in between.

To represent the partial days, we use the Duration class. A Duration is a span of time tracked as a total number of seconds plus nanoseconds.

First part runs from start to the first moment of the following day.

LocalDateTime firstMomentOfDayAfterStart = start.toLocalDate().plusDays(1).atStartOfDay();
Duration firstDayDuration = Duration.between( start , firstMomentOfDayAfterStart );

The last partial day runs from first moment of the same day as stop.

LocalDateTime firstMomentOfDayOfStop = stop.toLocalDate().atStartOfDay();
Duration lastDayDuration = Duration.between( firstMomentOfDayOfStop , stop );

We can convert each Duration to a number of hours.

int hoursFirstDay = firstDayDuration.toHours(); 
int hoursLastDay = lastDayDuration.toHours();

So we have variables defining these spans of time as shown in this text-as-diagram below. Remember these are Half-Open, where the ending of each span is exclusive.

[ start > firstMomentOfDayAfterStart ][ firstMomentOfDayAfterStart > firstMomentOfDayOfStop ][ firstMomentOfDayOfStop > stop ]

Now loop through the whole days in between that pair of partial days. Increment day-by-day, testing each successive day for being a weekday or weekend. Keep count of the weekdays we encounter. Use the handy DayOfWeek enum to compare.

int countWeekdays = 0;
LocalDateTime firstMomentOfSomeDay = firstMomentOfDayAfterStart
while( firstMomentOfSomeDay.isBefore( firstMomentOfDayOfStop ) ) {
    DayOfWeek dayOfWeek = firstMomentOfSomeDay.getDayOfWeek();
    if( dayOfWeek.equals( DayOfWeek.SATURDAY ) || dayOfWeek.equals( DayOfWeek.SUNDAY ) ) {
        // ignore this day.
    } else {
        countWeekdays ++ ; // Tally another weekday.
    }
    // Set up the next loop.
    firstMomentOfSomeDay = firstMomentOfSomeDay.plusDays( 1 );
}

We can use the TimeUnit enum to convert the count of whole days to a count of hours. This conversion assumes generic 24-hour days.

int hoursOfWholeDays = TimeUnit.DAYS.toHours( countWeekDays ) ;

Add those all up.

int totalHours = ( hoursFirstDay + hoursOfWholeDays + hoursLastDay ) ;

Done. Return the total hours.

return totalHours ;

If your data often includes long periods of time then you might consider optimizing performance by detecting a Monday and calculating number of whole weeks. I assume for tracking orders in a business scenario, the intervals are for a small number of days. So this optimization is not likely to be significant.

EnumSet

You can replace the line:

if( dayOfWeek.equals( DayOfWeek.SATURDAY ) || dayOfWeek.equals( DayOfWeek.SUNDAY ) )…

…with an EnumSet.

Set<DayOfWeek> weekend = EnumSet.of( DayOfWeek.SATURDAY , DayOfWeek.SUNDAY ) ;
…
if( weekend.contains( dayOfWeek ) ) …

Temporal Adjustor

See my answer to another Question for more info on detecting weekends using the nextWorkingDay and previousWorkingDay methods of the Temporals class. This class is found in the ThreeTen-Extra project that extends the java.time framework.

Furthermore, that class docs suggests it is relatively easy to write your own temporal adjustor to suit your particular business rules.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Also see [my Answer](http://stackoverflow.com/a/36878432/642706) to a similar Question where I use a [`TemporalQuery`](https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalQuery.html). – Basil Bourque Feb 27 '17 at 23:47
2

I find it cleaner with java.util.Calendar, here is an example getting number of hours since March 1st (8am) until current time :

final Calendar first = new Calendar.Builder()
        .setDate(2016, 2, 1).set(Calendar.AM_PM, 0).set(Calendar.HOUR, 8).build();
final Calendar second = Calendar.getInstance();

int numberOfDays = 0;
long numberOfHours = 0;
//Get number of full days
while(first.get(Calendar.DATE) != second.get(Calendar.DATE)){
    if(Calendar.SATURDAY != first.get(Calendar.DAY_OF_WEEK)
            && Calendar.SUNDAY != first.get(Calendar.DAY_OF_WEEK)){
        numberOfDays++;
    }
    first.roll(Calendar.DATE, true);
}
//Get number of hours in the remaining day
numberOfHours = TimeUnit.MILLISECONDS
        .toHours(second.getTimeInMillis() - first.getTimeInMillis());

System.out.println("Difference = " + 
        ( numberOfDays * 24 + numberOfHours ) + " hour(s)");
Benoit Vanalderweireldt
  • 2,925
  • 2
  • 21
  • 31
0

You could do something like this:

    Date date1 = new Date(2016, 3, 21), date2 = new Date(2016, 4, 9);

    int oneHour = 1000 * 60 * 60;

    //Note that this rounds down the number of hours/days
    int hours = (int)((date2.getTime() - date1.getTime()) / oneHour); 
    int days = hours / 24; 

    int day1, day2;
    //set the values of day: [Sun=0, Mon=1, Tue=2, Wed=3, Thur=4, Fri=5, Sat=6]
    //date.getDay() is supposed to do that, but it's deprecated

    int nWEdays = days/7*2;

    if(day2-day1 < 0) nWEdays += 2;
    else {
        if(day1 == 0 || day1 == 6) nWEdays++;
        else if(day2 == 0 || day2 == 6) nWEdays++;
    }
    int weekendHours = hours - nWEdays*24;
Maljam
  • 6,244
  • 3
  • 17
  • 30