tl;dr
java.time.LocalDate.of( 2018 , Month.JANUARY , 23 ) // A date-only class, built into Java 8 and later.
.with(
org.threeten.extra.Temporals.NextWorkingDay() // An implementation of `TemporalAdjuster` available in the ThreeTen-Extra library.
) // Returns a new distinct `LocalDate` object, per the Immutable Objects pattern.
java.time
The modern approach uses the java.time classes.
Define your start and stop dates. The LocalDate
class represents a date-only value without time-of-day and without time zone.
LocalDate start = LocalDate.of( 2018 , Month.JANUARY , 23 ) ;
LocalDate stop = start.plusMonths( 1 ) ;
Define the weekend specifically, using an EnumSet
of DayOfWeek
enum objects.
Set< DayOfWeek > weekend = EnumSet.of( DayOfWeek.SATURDAY , DayOfWeek.SUNDAY ) ;
Collect the dates matching our criteria. If you desire, you can optimize a bit by pre-sizing your List
of hits (don’t bother for a small number).
int days = (int)ChronoUnit.DAYS.between( start , stop ) ;
int weekendDaysEstimate = (int) ( ChronoUnit.WEEKS.between( start , stop ) * 2 ) ; // Approximate.
int initialCapacity = (days - weekendDaysEstimate + 7 ) ; // Adding seven arbitrarily for good measure so I don’t strain my brain worrying about exact number.
List< LocalDate > dates = new ArrayList<>( initialCapacity ) ;
Loop the days of your date range, incrementing a day at a time. Ask if each date’s day-of-week is found in our definition of weekend.
LocalDate ld = start ;
while( ld.isBefore( stop ) ) {
DayOfeek dow = ld.getDayOfWeek() ;
if( weekend.contains( dow ) ) {
// Just ignore it.
} else { // If not weekend, we care about this date. Collect it.
dates.add( ld ) ;
}
// Setup the next loop.
ld = ld.plusDays( 1 ) ;
}
[2018-01-23, 2018-01-24, 2018-01-25, 2018-01-26, 2018-01-29, 2018-01-30, 2018-01-31, 2018-02-01, 2018-02-02, 2018-02-05, 2018-02-06, 2018-02-07, 2018-02-08, 2018-02-09, 2018-02-12, 2018-02-13, 2018-02-14, 2018-02-15, 2018-02-16, 2018-02-19, 2018-02-20, 2018-02-21, 2018-02-22]
You could simplify this syntax, and make it easy for re-use, by writing your own implementation of a TemporalAdjuster
.
LocalDate ldNextWorkingDay = ld.with( myNextWorkingDayTemporalAdjuster ) ;
Oh, wait… Somebody already wrote such an adjuster. Available with the ThreeTen-Extra library that extends the functionality of the java.time classes.
Example. Much less code, and your intention in more clear. Note that we subtract a day from the start, to first consider the start date itself.
LocalDate ld = start.minusDays(1).with( org.threeten.extra.Temporals.NextWorkingDay() ) ; // Subtract one day to consider the start date itself.
while( ld.isBefore( stop ) ) {
dates.add( ld ) ;
// Setup the next loop.
ld = ld.with( org.threeten.extra.Temporals.NextWorkingDay() ) ;
} ;
Note that our logic here uses the Half-Open approach to defining a span of time. In this approach, the beginning is inclusive while the ending is exclusive. This approach is generally the best practice for date-time handling.
Finally, to get your count of days, Get the size of the collection of LocalDate
hits.
int countDays = dates.size() ;
If you were doing this chore an enormous number of times, you could optimize by calculating the partial weeks at the beginning and the ending, then calculate the number of whole weeks to be multiplied by two as an adjustment in total number of days. But for most apps I would guess such an optimization would not be material.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.