DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Calculate Number Of Work Days Between 2 Dates

10.13.2005
| 40216 views |
  • submit to reddit
        Hopefully this is quite a bit nicer than the old version, with comments etc. The call to fill the Holidays array has Western Australian holidays in it, but I'm sure you can still get the idea.

The application here seems to break some of the indenting, but hopefully it's still understandable.

<?php

    /**
	 * Calculates the number of work days between 2 given times
	 *
	 * @see get_holidays()
	 *
	 * @param date $start_date First date
	 * @param date $end_date Second date
	 * @param bool $workdays_only Whether to count only work days (eg. Mon-Fri)
	 * @param bool $skip_holidays Whether to use the get_holidays() function to skip holiday days as well
	 * @return int $workday_counter Number of workdays between the 2 dates
	 */
function date_difference($start_date, $end_date, $workdays_only = false, $skip_holidays = false){
    $start_date = strtotime($start_date);
    $end_date = strtotime($end_date);
    $seconds_in_a_day = 86400;
    $sunday_val = "0";
    $saturday_val = "6";
    $workday_counter = 0;
    $holiday_array = array();

    $ptr_year = intval(date("Y", $start_date));
    $holiday_array[$ptr_year] = get_holidays(date("Y", $start_date));

    for($day_val = $start_date; $day_val <= $end_date; $day_val+=$seconds_in_a_day){
        $pointer_day = date("w", $day_val);
        if($workdays_only == true){
            if(($pointer_day != $sunday_val) AND ($pointer_day != $saturday_val)){
                if($skip_holidays == true){
                    if(intval(date("Y", $day_val))!=$ptr_year){
                        $ptr_year = intval(date("Y", $day_val));
                        $holiday_array[$ptr_year] = get_holidays(date("Y", $day_val));
                    }
                    if(!in_array($day_val, $holiday_array[date("Y", $day_val)])){
                        $workday_counter++;
                    }
                }else{
                    $workday_counter++;
                }
            }
        }else{
            if($skip_holidays == true){
                if(intval(date("Y", $day_val))!=$ptr_year){
                    $ptr_year = intval(date("Y", $day_val));
                    $holiday_array[$ptr_year] = get_holidays(date("Y", $day_val));
                }
                if(!in_array($day_val, $holiday_array[date("Y", $day_val)])){
                    $workday_counter++;
                }
            }else{
                $workday_counter++;
            }
        }
    }
    return $workday_counter;
}

    /**
	 * Takes a date in yyyy-mm-dd format and returns a PHP timestamp
	 *
	 * @param string $MySqlDate
	 * @return unknown
	 */
function get_timestamp($MySqlDate){

    $date_array = explode("-",$MySqlDate); // split the array

    $var_year = $date_array[0];
    $var_month = $date_array[1];
    $var_day = $date_array[2];

    $var_timestamp = mktime(0,0,0,$var_month,$var_day,$var_year);
    return($var_timestamp); // return it to the user
}

    /**
	 * Returns the date of the $ord $day of the $month.
	 * For example ordinal_day(3, 'Sun', 5, 2001) returns the
     * date of the 3rd Sunday of May (ie. Mother's Day).
     *
     * @author  heymeadows@yahoo.com
	 *
	 * @param int $ord
	 * @param string $day (must be 3 char abbrev, per date("D);)
	 * @param int $month
	 * @param int $year
	 * @return unknown
	 */
function ordinal_day($ord, $day, $month, $year) {

    $firstOfMonth = get_timestamp("$year-$month-01");
    $lastOfMonth  = $firstOfMonth + date("t", $firstOfMonth) * 86400;
    $dayOccurs = 0;

    for ($i = $firstOfMonth; $i < $lastOfMonth ; $i += 86400){
        if (date("D", $i) == $day){
            $dayOccurs++;
            if ($dayOccurs == $ord){
                $ordDay = $i;
            }
        }
    }
    return $ordDay;
}

function memorial_day($inc_year){
    for($date_stepper = intval(date("t", strtotime("$inc_year-05-01"))); $date_stepper >= 1; $date_stepper--){
        if(date("l", strtotime("$inc_year-05-$date_stepper"))=="Monday"){
            return strtotime("$inc_year-05-$date_stepper");
            break;
        }
    }
}


    /**
	 * Looks through a lists of defined holidays and tells you which
	 * one is coming up next.
	 *
	 * @author heymeadows@yahoo.com
	 *
	 * @param int $inc_year The year we are looking for holidays in
	 * @return array
	 */
function get_holidays($inc_year){
    //$year = date("Y");
    $year = $inc_year;

    $holidays[] = new Holiday("New Year's Day", get_timestamp("$year-1-1"));
    $holidays[] = new Holiday("Australia Day", get_timestamp("$year-1-26"));
    $holidays[] = new Holiday("Labour Day", ordinal_day(1, 'Mon', 3, $year));
    $holidays[] = new Holiday("Anzac Day", get_timestamp("$year-4-25"));
    //$holidays[] = new Holiday("St. Patrick's Day", get_timestamp("$year-3-17"));
    // TODO: $holidays[] = new Holiday("Good Friday", easter_date($year));
    $holidays[] = new Holiday("Easter", easter_date($year));
    // TODO: $holidays[] = new Holiday("Easter Monday", easter_date($year));
    $holidays[] = new Holiday("Foundation Day", ordinal_day(1, 'Mon', 6, $year));
    $holidays[] = new Holiday("Queen's Birthday", ordinal_day(1, 'Mon', 10, $year));
    //$holidays[] = new Holiday("Memorial Day", memorial_day($year));
    //$holidays[] = new Holiday("Mother's Day", ordinal_day(2, 'Sun', 5, $year));
    //$holidays[] = new Holiday("Father's Day", ordinal_day(3, 'Sun', 6, $year));
    //$holidays[] = new Holiday("Independence Day", get_timestamp("$year-7-4"));
    //$holidays[] = new Holiday("Labor Day", ordinal_day(1, 'Mon', 9, $year));
    $holidays[] = new Holiday("Christmas", get_timestamp("$year-12-25"));
    $holidays[] = new Holiday("Boxing Day", get_timestamp("$year-12-26"));

    $numHolidays = count($holidays) - 1;
    $out_array = array();

    for ($i = 0; $i < $numHolidays; $i++){
        $out_array[] = $holidays[$i]->date;
    }
    unset($holidays);
    return $out_array;
}

class Holiday{
    //var $name;
    //var $date;
    public $name;
    public $date;

    // Contructor to define the details of each holiday as it is created.
    function holiday($name, $date){
        $this->name   = $name;   // Official name of holiday
        $this->date   = $date;   // UNIX timestamp of date
    }
}

?>
    

Comments

Snippets Manager replied on Mon, 2011/06/13 - 9:52pm

Thank you very much for sharing this script I have made some changes and wanted to share. I wanted to use this script to work out Annual leave and in Western Australia we roll Public Holidays over to Monday if they fall on the weekend :) Ive added a new function to work out if the Public Holiday is on the weekend and if so roll it forward to the Monday. I have also fixed up Easter, so it shows the Easter Monday and Good Friday. New Function function check_day($holiday_date){ $holiday_date2 = date("l",get_timestamp($holiday_date)); if($holiday_date2 =="Saturday"){ $NewDate = (get_timestamp($holiday_date) + 172800); } elseif($holiday_date2 =="Sunday"){ $NewDate = (get_timestamp($holiday_date) + 86400); } else { $NewDate = get_timestamp($holiday_date); } return $NewDate; } The new function is called in the Get_holidays function function get_holidays($inc_year){ //$year = date("Y"); $year = $inc_year; $holidays[] = new Holiday("New Year's Day", check_day("$year-1-1")); $holidays[] = new Holiday("Australia Day", check_day("$year-1-26")); $holidays[] = new Holiday("Labour Day", ordinal_day(1, 'Mon', 3, $year)); $holidays[] = new Holiday("Anzac Day", check_day("$year-4-25")); //$holidays[] = new Holiday("St. Patrick's Day", get_timestamp("$year-3-17")); $holidays[] = new Holiday("Good Friday", (easter_date($year)-172800)); // Easter - 2 day //$holidays[] = new Holiday("Easter", easter_date($year)); $holidays[] = new Holiday("Easter Monday", (easter_date($year)+86400)); // Easter + 1 day $holidays[] = new Holiday("Foundation Day", ordinal_day(1, 'Mon', 6, $year)); $holidays[] = new Holiday("Queen's Birthday", ordinal_day(1, 'Mon', 10, $year)); //$holidays[] = new Holiday("Memorial Day", memorial_day($year)); //$holidays[] = new Holiday("Mother's Day", ordinal_day(2, 'Sun', 5, $year)); //$holidays[] = new Holiday("Father's Day", ordinal_day(3, 'Sun', 6, $year)); //$holidays[] = new Holiday("Independence Day", get_timestamp("$year-7-4")); //$holidays[] = new Holiday("Labor Day", ordinal_day(1, 'Mon', 9, $year)); $holidays[] = new Holiday("Christmas", check_day("$year-12-25")); $holidays[] = new Holiday("Boxing Day", check_day("$year-12-26")); $numHolidays = count($holidays) - 1; $out_array = array(); for ($i = 0; $i < $numHolidays; $i++){ $out_array[] = $holidays[$i]->date; } unset($holidays); return $out_array; } PS. My coding skills as out dated so feel free to update my bad coding :)

Snippets Manager replied on Mon, 2011/06/13 - 9:52pm

beylah I think this is what you are after $start_date = "2011-1-3"; $end_date = "2011-1-5"; $numberofdays = date_difference($start_date, $end_date, true, true);

Snippets Manager replied on Wed, 2009/12/09 - 4:00pm

going back to the original snippet - where do i add the 2 dates

Snippets Manager replied on Thu, 2009/09/10 - 4:42pm

I'm new to Dzone, so hope this is the right place to post this. I added some United States holidays, including USPS holidays. Hope this helps someone else. Thanks so much, oceanic, for posting this here! function veterans_day($inc_year){ if(date("l", strtotime("$inc_year-11-11"))=="Sunday"){ return strtotime("$inc_year-11-12"); } else if(date("l", strtotime("$inc_year-11-11"))=="Saturday"){ return strtotime("$inc_year-11-10"); } else { return strtotime("$inc_year-11-11"); } } $holidays[] = new Holiday("New Year's Day", get_timestamp("$year-1-1")); $holidays[] = new Holiday("Martin Luther King Jr Day", ordinal_day(3, 'Mon', 1, $year)); $holidays[] = new Holiday("Presidents Day", ordinal_day(3, 'Mon', 2, $year)); $holidays[] = new Holiday("Memorial Day", memorial_day($year)); $holidays[] = new Holiday("Independence Day", get_timestamp("$year-7-4")); $holidays[] = new Holiday("Labor Day", ordinal_day(1, 'Mon', 9, $year)); $holidays[] = new Holiday("Columbus Day", ordinal_day(2, 'Mon', 10, $year)); // Veteran's day is Nov 11, but if it falls on Saturday, it's observed on Friday; on Sunday, it's observed on Monday $holidays[] = new Holiday("Veterans Day", veterans_day($year)); $holidays[] = new Holiday("Thanksgiving", ordinal_day(4, 'Thurs', 11, $year)); $holidays[] = new Holiday("Day After Thanksgiving", ordinal_day(4, 'Fri', 11, $year));

Snippets Manager replied on Mon, 2012/05/07 - 2:15pm

Hi Will, That's fine - the more code snippets, the better. I grabbed this from somewhere else anyway, I didn't write it myself. I just wanted to put it in here as a way of storing it somewhere I can find it again. Drew

Snippets Manager replied on Mon, 2012/05/07 - 2:15pm

I posted my Informix 4GL version of something similar which doesn't cycle through the days. I'm not competing or anything, just saw yours and thought I'd post my algorithm.