Counting Types of Days in PHP

Since I work on our HR team at Automattic, sometimes I need to write code dealing with payroll. When someone starts or leaves we have to pay them for a partial period, which is based on the number of week days. Originally I wrote a simple function, but I set out to make it more useable. Here is what I came up with…

/**
 * Counts the days (optionally limited by type of day) between (inclusive) two dates.
 *
 * @param string $start_date First day (Y-m-d format).
 * @param string $end_date   Last day (Y-m-d format).
 * @param array  $types      Optional. Types of days to count. Default to all types
 *
 * @return int Number of days matching the $types.
 */
function get_days_between_dates( $start_date, $end_date, $types = array() ) {
	$count = 0;

	$included_day_type_indexes = array();
	if ( empty( $types ) ) {
		$included_day_type_indexes = range( 1, 7 );
	} else {
		foreach ( $types as $type ) {
			switch ( strtolower( $type ) ) {
				case 'weekday':
					$included_day_type_indexes = array_merge( $included_day_type_indexes, range( 1, 5 ) );
					break;
				case 'weekend':
					$included_day_type_indexes = array_merge( $included_day_type_indexes, range( 6, 7 ) );
					break;
				case 'monday':
				case 'mon':
					$included_day_type_indexes[] = 1;
					break;
				case 'tuesday':
				case 'tues':
				case 'tue':
				case 'tu':
					$included_day_type_indexes[] = 2;
					break;
				case 'wednesday':
				case 'wed':
					$included_day_type_indexes[] = 3;
					break;
				case 'thursday':
				case 'thurs':
				case 'thur':
				case 'thu':
				case 'th':
					$included_day_type_indexes[] = 4;
					break;
				case 'friday':
				case 'fri':
					$included_day_type_indexes[] = 5;
					break;
				case 'saturday':
				case 'caturday':
				case 'sat':
					$included_day_type_indexes[] = 6;
					break;
				case 'sunday':
				case 'sun':
					$included_day_type_indexes[] = 7;
					break;
			}
		}

		$included_day_type_indexes = array_unique( $included_day_type_indexes );
	}

	$date = strtotime( $start_date );
	$end = strtotime( $end_date );
	while ( $date <= $end ) {
		if ( in_array( date( 'N', $date ), $included_day_type_indexes ) ) {
			$count++;
		}

		$date = strtotime( '+1 day', $date );
	}

	return $count;
}

/*** EXAMPLES ***/

echo get_days_between_dates( '2017-08-21', '2017-09-03' ) . "\n";
echo get_days_between_dates( '2017-08-21', '2017-09-03', array( 'weekday', 'weekend' ) ) . "\n";
echo get_days_between_dates( '2017-08-21', '2017-09-03', array( 'mon' ) ) . "\n";
echo get_days_between_dates( '2017-08-21', '2017-09-03', array( 'weekday' ) ) . "\n";
echo get_days_between_dates( '2017-08-21', '2017-09-03', array( 'mon', 'wednesday', 'fri' ) ) . "\n";

This is the output of the examples…

14
14
2
10
6

What do you think? What would you do different?

I put the function up on GitHub. Submit a pull request if you have improvements.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s