Skip to content

Instantly share code, notes, and snippets.

@rinogo
Created November 26, 2018 16:45
Show Gist options
  • Save rinogo/eec3c121613d7080439f9cbc1101387d to your computer and use it in GitHub Desktop.
Save rinogo/eec3c121613d7080439f9cbc1101387d to your computer and use it in GitHub Desktop.
Simple unit-tested class to calculate federal holiday dates for the United States. Methods are included for determining if a date (timestamp) is considered a date and for accessing holidays by name and by timestamp.
<?php
//Adapted by rich at byu.net from https://www.damia.no/calculating-u-s-federal-holidays-with-php/
class UsHolidays {
private $year;
private $list;
const ONE_DAY = 86400; //Number of seconds in one day
function __construct($year = null, $timezone = "America/Denver") {
try {
$original_time_zone = date_default_timezone_get();
if(!date_default_timezone_set($timezone)) {
throw new Exception("$timezone is not a valid timezone.");
}
$this->year = (is_null($year)) ? (int) date("Y") : (int) $year;
if(!is_int($this->year) || $this->year < 1997) {
throw new Exception("$year is not a valid year. Valid values are integers greater than 1996.");
}
$this->setList();
} finally {
date_default_timezone_set($original_time_zone);
}
}
private function adjustFixedHoliday($timestamp) {
$weekday = date("w", $timestamp);
if($weekday == 0) {
return $timestamp + self::ONE_DAY; //NOTE: Potential daylight savings issue for holidays that coincide with/are adjacent to daylight savings "transition" dates?
}
if($weekday == 6) {
return $timestamp - self::ONE_DAY; //NOTE: Potential daylight savings issue for holidays that coincide with/are adjacent to daylight savings "transition" dates?
}
return $timestamp;
}
private function setList() {
$this->list = array();
$this->list[$this->adjustFixedHoliday(mktime(0, 0, 0, 1, 1, $this->year))] = "New Year's Day"; //January 1st (if not Saturday/Sunday)
$this->list[strtotime("Third Monday of January $this->year")] = "Martin Luther King, Jr. Day"; //3rd Monday of January
$this->list[strtotime("Third Monday of February $this->year")] = "Presidents' Day"; //3rd Monday of February
$this->list[strtotime("Last Monday of May $this->year")] = "Memorial Day"; //Last Monday of May
$this->list[$this->adjustFixedHoliday(mktime(0, 0, 0, 7, 4, $this->year))] = "Independence Day"; //July 4 (if not Saturday/Sunday)
$this->list[strtotime("First Monday of September $this->year")] = "Labor Day"; //1st Monday of September
$this->list[strtotime("Second Monday of October $this->year")] = "Columbus Day"; //2nd Monday of October
$this->list[$this->adjustFixedHoliday(mktime(0, 0, 0, 11, 11, $this->year))] = "Veterans Day"; //November 11 (if not Saturday/Sunday)
$this->list[strtotime("Fourth Thursday of November $this->year")] = "Thanksgiving Day"; //4th Thursday of November
$this->list[$this->adjustFixedHoliday(mktime(0, 0, 0, 12, 25, $this->year))] = "Christmas Day"; //December 25 every year (if not Saturday/Sunday)
}
public function getList() {
return $this->list;
}
public function getListByName() {
return array_flip($this->list);
}
public function isHoliday($timestamp) {
return array_key_exists($timestamp, $this->list);
}
}
<?php
class UsHolidaysTest extends PHPUnit_Framework_TestCase {
/**
* @group unit
*/
public function testGetList() {
$offset = get_timezone_offset("America/Denver");
//2013
$holidays = new UsHolidays(2013);
$list = $holidays->getList();
$this->assertEquals($list[get_date_time("1/1/2013")], "New Year's Day");
$this->assertEquals($list[get_date_time("1/21/2013")], "Martin Luther King, Jr. Day");
$this->assertEquals($list[get_date_time("2/18/2013")], "Presidents' Day");
$this->assertEquals($list[get_date_time("5/27/2013")], "Memorial Day");
$this->assertEquals($list[get_date_time("7/4/2013")], "Independence Day");
$this->assertEquals($list[get_date_time("9/2/2013")], "Labor Day");
$this->assertEquals($list[get_date_time("10/14/2013")], "Columbus Day");
$this->assertEquals($list[get_date_time("11/11/2013")], "Veterans Day");
$this->assertEquals($list[get_date_time("11/28/2013")], "Thanksgiving Day");
$this->assertEquals($list[get_date_time("12/25/2013")], "Christmas Day");
//2014
$holidays = new UsHolidays(2014);
$list = $holidays->getList();
$this->assertEquals($list[get_date_time("1/1/2014")], "New Year's Day");
$this->assertEquals($list[get_date_time("1/20/2014")], "Martin Luther King, Jr. Day");
$this->assertEquals($list[get_date_time("2/17/2014")], "Presidents' Day");
$this->assertEquals($list[get_date_time("5/26/2014")], "Memorial Day");
$this->assertEquals($list[get_date_time("7/4/2014")], "Independence Day");
$this->assertEquals($list[get_date_time("9/1/2014")], "Labor Day");
$this->assertEquals($list[get_date_time("10/13/2014")], "Columbus Day");
$this->assertEquals($list[get_date_time("11/11/2014")], "Veterans Day");
$this->assertEquals($list[get_date_time("11/27/2014")], "Thanksgiving Day");
$this->assertEquals($list[get_date_time("12/25/2014")], "Christmas Day");
//2015
$holidays = new UsHolidays(2015);
$list = $holidays->getList();
$this->assertEquals($list[get_date_time("1/1/2015")], "New Year's Day");
$this->assertEquals($list[get_date_time("1/19/2015")], "Martin Luther King, Jr. Day");
$this->assertEquals($list[get_date_time("2/16/2015")], "Presidents' Day");
$this->assertEquals($list[get_date_time("5/25/2015")], "Memorial Day");
$this->assertEquals($list[get_date_time("7/3/2015")], "Independence Day");
$this->assertEquals($list[get_date_time("9/7/2015")], "Labor Day");
$this->assertEquals($list[get_date_time("10/12/2015")], "Columbus Day");
$this->assertEquals($list[get_date_time("11/11/2015")], "Veterans Day");
$this->assertEquals($list[get_date_time("11/26/2015")], "Thanksgiving Day");
$this->assertEquals($list[get_date_time("12/25/2015")], "Christmas Day");
//2016
$holidays = new UsHolidays(2016);
$list = $holidays->getList();
$this->assertEquals($list[get_date_time("1/1/2016")], "New Year's Day");
$this->assertEquals($list[get_date_time("1/18/2016")], "Martin Luther King, Jr. Day");
$this->assertEquals($list[get_date_time("2/15/2016")], "Presidents' Day");
$this->assertEquals($list[get_date_time("5/30/2016")], "Memorial Day");
$this->assertEquals($list[get_date_time("7/4/2016")], "Independence Day");
$this->assertEquals($list[get_date_time("9/5/2016")], "Labor Day");
$this->assertEquals($list[get_date_time("10/10/2016")], "Columbus Day");
$this->assertEquals($list[get_date_time("11/11/2016")], "Veterans Day");
$this->assertEquals($list[get_date_time("11/24/2016")], "Thanksgiving Day");
$this->assertEquals($list[get_date_time("12/26/2016")], "Christmas Day");
//2017
$holidays = new UsHolidays(2017);
$list = $holidays->getList();
$this->assertEquals($list[get_date_time("1/2/2017")], "New Year's Day");
$this->assertEquals($list[get_date_time("1/16/2017")], "Martin Luther King, Jr. Day");
$this->assertEquals($list[get_date_time("2/20/2017")], "Presidents' Day");
$this->assertEquals($list[get_date_time("5/29/2017")], "Memorial Day");
$this->assertEquals($list[get_date_time("7/4/2017")], "Independence Day");
$this->assertEquals($list[get_date_time("9/4/2017")], "Labor Day");
$this->assertEquals($list[get_date_time("10/9/2017")], "Columbus Day");
$this->assertEquals($list[get_date_time("11/10/2017")], "Veterans Day");
$this->assertEquals($list[get_date_time("11/23/2017")], "Thanksgiving Day");
$this->assertEquals($list[get_date_time("12/25/2017")], "Christmas Day");
//2018
$holidays = new UsHolidays(2018);
$list = $holidays->getList();
$this->assertEquals($list[get_date_time("1/1/2018")], "New Year's Day");
$this->assertEquals($list[get_date_time("1/15/2018")], "Martin Luther King, Jr. Day");
$this->assertEquals($list[get_date_time("2/19/2018")], "Presidents' Day");
$this->assertEquals($list[get_date_time("5/28/2018")], "Memorial Day");
$this->assertEquals($list[get_date_time("7/4/2018")], "Independence Day");
$this->assertEquals($list[get_date_time("9/3/2018")], "Labor Day");
$this->assertEquals($list[get_date_time("10/8/2018")], "Columbus Day");
$this->assertEquals($list[get_date_time("11/12/2018")], "Veterans Day");
$this->assertEquals($list[get_date_time("11/22/2018")], "Thanksgiving Day");
$this->assertEquals($list[get_date_time("12/25/2018")], "Christmas Day");
//2019
$holidays = new UsHolidays(2019);
$list = $holidays->getList();
$this->assertEquals($list[get_date_time("1/1/2019")], "New Year's Day");
$this->assertEquals($list[get_date_time("1/21/2019")], "Martin Luther King, Jr. Day");
$this->assertEquals($list[get_date_time("2/18/2019")], "Presidents' Day");
$this->assertEquals($list[get_date_time("5/27/2019")], "Memorial Day");
$this->assertEquals($list[get_date_time("7/4/2019")], "Independence Day");
$this->assertEquals($list[get_date_time("9/2/2019")], "Labor Day");
$this->assertEquals($list[get_date_time("10/14/2019")], "Columbus Day");
$this->assertEquals($list[get_date_time("11/11/2019")], "Veterans Day");
$this->assertEquals($list[get_date_time("11/28/2019")], "Thanksgiving Day");
$this->assertEquals($list[get_date_time("12/25/2019")], "Christmas Day");
//2020
$holidays = new UsHolidays(2020);
$list = $holidays->getList();
$this->assertEquals($list[get_date_time("1/1/2020")], "New Year's Day");
$this->assertEquals($list[get_date_time("1/20/2020")], "Martin Luther King, Jr. Day");
$this->assertEquals($list[get_date_time("2/17/2020")], "Presidents' Day");
$this->assertEquals($list[get_date_time("5/25/2020")], "Memorial Day");
$this->assertEquals($list[get_date_time("7/3/2020")], "Independence Day");
$this->assertEquals($list[get_date_time("9/7/2020")], "Labor Day");
$this->assertEquals($list[get_date_time("10/12/2020")], "Columbus Day");
$this->assertEquals($list[get_date_time("11/11/2020")], "Veterans Day");
$this->assertEquals($list[get_date_time("11/26/2020")], "Thanksgiving Day");
$this->assertEquals($list[get_date_time("12/25/2020")], "Christmas Day");
}
}
<?php
//Convert a date in the format mm/dd/yyyy to its equivalent time in seconds since the Unix Epoch.
function get_date_time($date, $timezone_str = "America/Denver") {
$tokens = explode("/", $date);
$timezone = new DateTimeZone($timezone_str);
$dt = DateTime::createFromFormat("!m/d/Y", date("m/d/Y", mktime(0, 0, 0, $tokens[0], $tokens[1], $tokens[2])), $timezone);
return $dt->getTimestamp();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment