【发布时间】:2023-03-08 16:35:01
【问题描述】:
我有一个工作的 symfony 项目,其中包括一个 Holiday 类,其中包含几个分组的静态函数,用于计算非假日工作日。代码的核心取自 this thread 中的几个答案。
我在我的代码库中使用静态方法,包括树枝扩展、报告、图表创建等。
最大的缺点是我必须定期使用这些方法并手动输入来年的假期(是的,我知道我可以一次完成几年),但偶尔会有“假期”我添加了诸如由于恶劣天气而导致的休息日之类的事情。手动添加假期并将代码推送到我的 git 存储库只是感觉“错误”,或者至少不优雅。
该解决方案似乎将假期放入数据库,并且再也不会接触代码。这意味着使用教义,但这意味着需要一些依赖注入来让实体管理器访问我的静态方法,这又一次让人感觉不那么优雅。
那么解决办法是什么??
这是我的Holiday 课程,尽管这里的代码非常适合我的需要。我正在寻找一种优雅的方式将$holidays 数组移动到数据库中。
<?php
namespace App\Controller;
use DateInterval;
use DatePeriod;
use DateTime;
use Exception;
class Holiday
{
private static $workingDays = [1, 2, 3, 4, 5]; # date format = N (1 = Monday, ...)
/**
* Is submitted date a holiday?
*
* @param DateTime $date
* @return bool
*/
public static function isHoliday(DateTime $date): bool
{
$holidays = self::getHolidays();
return
in_array($date->format('Y-m-d'), $holidays) ||
in_array($date->format('*-m-d'), $holidays);
}
public static function isWorkDay(DateTime $date): bool
{
if (!in_array($date->format('N'), self::$workingDays)) {
return false;
}
if (self::isHoliday($date)) {
return false;
}
return true;
}
/**
* Count number of weekdays within a given date span, excluding holidays
*
* @param DateTime $from
* @param DateTime $to
* @return int
* @throws Exception
*/
public static function countWeekDays(DateTime $from, DateTime $to = null)
{
if (is_null($to)) {
return null;
}
// from stackoverflow:
// http://stackoverflow.com/questions/336127/calculate-business-days#19221403
$from = clone($from);
$from->setTime(0, 0, 0);
$to = clone($to);
$to->setTime(0, 0, 0);
$interval = new DateInterval('P1D');
$to->add($interval);
$period = new DatePeriod($from, $interval, $to);
$days = 0;
/** @var DateTime $date */
foreach ($period as $date) {
if (self::isWorkDay($date)) {
$days++;
}
}
return $days;
}
/**
* Return count of weekdays in given month
*
* @param int $month
* @param int $year
* @return int
* @throws Exception
*/
public static function countWeekDaysInMonthToDate(int $month, int $year): int
{
$d1 = new DateTime($year . '-' . $month . '-01');
$d2 = new DateTime($d1->format('Y-m-t'));
$today = new DateTime();
return self::countWeekDays($d1, min($d2, $today));
}
/**
* Returns an array of strings representing holidays in format 'Y-m-d'
*
* @return array
*/
private static function getHolidays(): array
{
// TODO: Move holidays to database (?)
$holidays = ['*-12-25', '*-01-01', '*-07-04',
'2017-04-14', # Good Friday
'2017-05-29', # Memorial day
'2017-08-28', # Hurricane Harvey closure
'2017-08-29', # Hurricane Harvey closure
'2017-08-30', # Hurricane Harvey closure
'2017-08-31', # Hurricane Harvey closure
'2017-09-01', # Hurricane Harvey closure
'2017-09-04', # Labor day
'2017-11-23', # Thanksgiving
'2017-11-24', # Thanksgiving
#'2018-03-30', # Good Friday
'2018-05-28', # Memorial day
'2018-09-03', # Labor day
'2018-11-22', # Thanksgiving
'2018-11-23', # Thanksgiving
'2018-12-24', # Christmas Eve
'2018-12-31', # New Year's Eve
'2019-04-19', # Good Friday
'2019-05-27', # Memorial day
'2019-09-02', # Labor day
'2019-11-28', # Thanksgiving
'2019-11-29', # Thanksgiving
]; # variable and fixed holidays
return $holidays;
}
}
【问题讨论】:
-
您将希望将relative dates 用于您的假期,例如
fourth Thursday of November或fourth Thurdsay of November + 1 day,并使用要影响的年份修改DateTimeImmutale对象。喜欢:3v4l.org/pra1L 我创建了一个类似的服务来做同样的事情,但我受到 NDA 的约束,否则我会提供更多帮助。 -
感谢@fyrye,但这对于随机的日子(例如因恶劣天气而关闭)无济于事,因此失去了数据库的灵活性。
-
这是意料之中的,因为从技术上讲,组织关闭不是一个可观察到的假期,也不是静态定义的。但是很容易解决并且可以在没有数据库的情况下定义,例如读取包含文件中
$_POST值数组的CSV 或var_export。例如:$holidays = include '/path/to/file.php';和 file.php 包含return array('....');