PHPackages                             phpexperts/workday-planner - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. phpexperts/workday-planner

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

phpexperts/workday-planner
==========================

Given a date range, this will give you all of the workdays for that country.

v1.3.0(11mo ago)251.5k5[14 issues](https://github.com/phpexpertsinc/WorkdayPlanner/issues)MITPHPPHP &gt;=8.1

Since Aug 10Pushed 11mo ago2 watchersCompare

[ Source](https://github.com/phpexpertsinc/WorkdayPlanner)[ Packagist](https://packagist.org/packages/phpexperts/workday-planner)[ Docs](https://github.com/phpexpertsinc/workday-planner)[ RSS](/packages/phpexperts-workday-planner/feed)WikiDiscussions master Synced 3d ago

READMEChangelogDependencies (5)Versions (6)Used By (0)

The PHP Workday Planner
=======================

[](#the-php-workday-planner)

[![Travis CI](https://camo.githubusercontent.com/e5c7f62221f83f627b5878ac7653e2427af279bbf83877ad6154d3f219767b22/68747470733a2f2f7472617669732d63692e6f72672f70687065787065727473696e632f576f726b646179506c616e6e65722e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/phpexpertsinc/WorkdayPlanner)[![Maintainability](https://camo.githubusercontent.com/1a43ac7bcc8dbef2aabd45b96b4d48c35b9d5b233ddee28b50b06bdac5dc79a3/68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f37393635366138626534636237363762353163652f6d61696e7461696e6162696c697479)](https://codeclimate.com/github/phpexpertsinc/WorkdayPlanner/maintainability)[![Test Coverage](https://camo.githubusercontent.com/8b6fbe3379ab3e71ef3e51d0f6ff0138ad85e298c719ad8cf5436c3e8c0ab34d/68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f37393635366138626534636237363762353163652f746573745f636f766572616765)](https://codeclimate.com/github/phpexpertsinc/WorkdayPlanner/test_coverage)

Installation
------------

[](#installation)

Run `composer require phpexperts/workday-planner`

The Problem
-----------

[](#the-problem)

Imagine that you have to schedule a task to run every workday in your country over a given time period.

In order to do this, you first have to figure out what the workdays are, and the weekends. Simple enough, right? But then you remember: "Hey, what about Christmas? and all those other holidays?"

So you dutifully go about detecting those, too. Only to have your clients complaining on the Monday after the Fourth of July. Because, you see, at least in the United States, holidays that occur on Saturdays are observed on the previous Friday, while holidays that occur on Sundays are observed on the next Monday.

The Solution
------------

[](#the-solution)

With this package, all of these technicalities are handled for you. You give it a date range, and it will dutifully spit out the workdays, keeping in mind both the actual and observed U.S. national holidays common to most employers.

Ad-hoc Workday Verification
---------------------------

[](#ad-hoc-workday-verification)

```
    use PHPExperts\WorkdayPlanner\WorkdayDetector;

    function isWorkday($dateString) {
        $isWorkday = WorkdayDetector::isWorkday(new \DateTime($dateString));
        $isOrIsnt = $isWorkday ? 'is' : 'is not';

        echo "$dateString $isOrIsnt a work day.\n";
    }

    // Is Friday, 10 August 2018, a workday?
    isWorkday('10 August 2018');    // Workday
    isWorkday('11 August 2018');    // Weekend
    isWorkday('25 December 2018');  // Fixed holiday
    isWorkday('22 November 2018');  // Floating holiday

     /* Output:
     10 August 2018 is a work day.
     11 August 2018 is not a work day.
     25 December 2018 is not a work day.
     22 November 2018 is not a work day.
     */
```

Floating Holidays
-----------------

[](#floating-holidays)

Some holidays are based upon a certain day of the month, instead of a fixed date. These are called "floating holidays".

The date spec looks like this for Thanksgiving Day:

```
  {
    "name": "Thanksgiving Day",
    "type": "day",
    "when": "fourth Thursday of November"
  }
```

Examples:

```
    WorkdayDetector::isWorkday(new \DateTime('2018-11-22')); // false; Thanksgiving Day
    WorkdayDetector::isWorkday(new \DateTime('2019-11-28')); // false; Thanksgiving Day

    echo (new HolidayDetector())         // 2018-11-22
        ->getHoliday('Thanksgiving Day')
        ->format('Y-m-d');

    echo (new HolidayDetector())         // 2018-11-28
        ->changeYear(2019)
        ->getHoliday('Thanksgiving Day')
        ->format('Y-m-d');
```

### Observerable Holidays

[](#observerable-holidays)

```
    // The Fourth of July occurs on a Sunday in 2021, so the following Monday is not
    // a workday.

    use PHPExperts\WorkdayPlanner\WorkdayPlanner;

    $planner = new WorkdayPlanner(new \DateTime('2021-07-01'), new \DateTime('2021-07-06'));

    echo json_encode(
        $planner->getWorkdays(),
        JSON_PRETTY_PRINT
    );

    /* Output:
    [
        "2021-07-01",
        "2021-07-02",
        "2021-07-06"
    ]
    */
```

### Ad-hoc Holiday Verification

[](#ad-hoc-holiday-verification)

```
    $detector = new HolidayDetector();
    var_dump([
        $detector->isHoliday('2021-07-04'), // The actual holiday.
        $detector->isHoliday('2021-07-05'), // The observed holiday
    ]);

    $detector = new HolidayDetector();
    $detector->changeYear(2021);
    print_r([
        'actual' => $detector->getHoliday('Independence Day')->format('l jS \of F Y'),
        'observed' => $detector->getHoliday('Independence Day (Observed)')->format('l jS \of F Y'),
    ]);

    /* Output:
    array(2) {
      [0] => bool(true)
      [1] => bool(true)
    }

    Array
    (
        [actual] => Sunday 4th of July 2021
        [observed] => Monday 5th of July 2021
    )
    */
```

Access to the Workdays
----------------------

[](#access-to-the-workdays)

There are several ways to access the workdays.

The Workday Planner can be accessed like an array, or as an iterator, or you can just get a simple array of all the workday dates.

### Simple access

[](#simple-access)

```
    $planner = new WorkdayPlanner(new \DateTime('2021-07-01'), new \DateTime('2021-07-06'));

    echo json_encode(
        $planner->getWorkdays(),
        JSON_PRETTY_PRINT
    );

    /* Output:
    [
        "2021-07-01",
        "2021-07-02",
        "2021-07-06"
    ]
    */
```

### As an iterator

[](#as-an-iterator)

```
    $planner = new WorkdayPlanner(new \DateTime('2021-07-01'), new \DateTime('2021-07-06'));
    /** @var \DateTime $workday */
    foreach ($planner as $workday) {
        // ...
    }
```

### As an array

[](#as-an-array)

```
    $planner = new WorkdayPlanner(new \DateTime('2021-07-01'), new \DateTime('2021-07-06'));

    // Is it a workday?
    if (isset($planner['2021-07-01'])) {
        echo "Yes, it is.\n";
    }
    else {
        echo "No, it is not.\n";
    }

    // Since '2021-07-01' is the first day in the range, it is equal to $planner[0].
    echo ($planner[0] === $planner['2021-07-01']) ? 'Strictly equal!' : 'Not equal.';

    /* Output:
    Yes, it is.
    Strictly equal!
    */
```

### Manually remove a workday

[](#manually-remove-a-workday)

Workdays can be manually removed, per your policies:

```
    $planner = new WorkdayPlanner(new \DateTime('2021-07-01'), new \DateTime('2021-07-06'));
    unset($planner['2021-07-01']);

    // Is it a workday?
    if (isset($planner['2021-07-01'])) {
        echo "Yes, it is.\n";
    }
    else {
        echo "No, it is not.\n";
    }

    /* Output:
    No, it is not.
    */
```

Behavior Documentation
----------------------

[](#behavior-documentation)

The project currently has 100% code coverage via unit tests.

Here is the behavior documentation, generated by PHPUnit's testdox:

### HolidayDetector

[](#holidaydetector)

1. Can parse fixed holiday dates
2. Can parse floating holiday dates
3. Can determine if a date is a holiday
4. Shows error for unimplemented country
5. Shows error for invalid data
6. Shows error for invalid holiday spec
7. Properly handles unknown holidays
8. Will report friday as the observed day for saturday holidays
9. Will report friday as the observed day for sunday holidays

### WorkdayDetector

[](#workdaydetector)

1. Can determine if a date is a workday

### WorkdayPlanner

[](#workdayplanner)

1. Will create a date range of workdays
2. Will properly offset saturday holidays
3. Will properly offset sunday holidays
4. Can iterate through each date
5. The number of workdays is countable
6. Can access dates via the array operator with a numeric index
7. Can access dates via the array operator with a date index
8. Can use numeric isset on a workday
9. Can use date isset on a workday
10. Can remove a work day via unset
11. Properly handles a start date later than the end date
12. Properly handles a start date equal to the end date
13. Properly handles invalid dates
14. Wont allow manually adding workdays

Credits
=======

[](#credits)

Created by Theodore R. Smith , mostly in one day.

A [PHP Experts, Inc.](https://www.phpexperts.pro/), project.

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance40

Moderate activity, may be stable

Popularity26

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity75

Established project with proven stability

 Bus Factor1

Top contributor holds 95.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~622 days

Total

5

Last Release

345d ago

PHP version history (3 changes)v1.0.0PHP ^7.1

v1.1.1PHP &gt;=7.1

v1.2.0PHP &gt;=8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/3f3a2dd16766f6b03c330e65aaca9dfb97f1bbbb41c5e2af5681f58f670b7917?d=identicon)[hopeseekr](/maintainers/hopeseekr)

---

Top Contributors

[![hopeseekr](https://avatars.githubusercontent.com/u/1125541?v=4)](https://github.com/hopeseekr "hopeseekr (23 commits)")[![peter279k](https://avatars.githubusercontent.com/u/9021747?v=4)](https://github.com/peter279k "peter279k (1 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/phpexperts-workday-planner/health.svg)

```
[![Health](https://phpackages.com/badges/phpexperts-workday-planner/health.svg)](https://phpackages.com/packages/phpexperts-workday-planner)
```

###  Alternatives

[wdev-rs/laravel-analytics

Collect page view data in your application without third party tracking

151.2k](/packages/wdev-rs-laravel-analytics)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
