iansltx / business-days
一种基于工作日而非日历日计算日期期间的方法
Requires
- php: >=5.5.0
Requires (Dev)
- codeclimate/php-test-reporter: dev-master
- phpunit/phpunit: 4.*
- scrutinizer/ocular: ~1.1
README
BusinessDays 是一组用于处理某些(非工作日/假日)不计入日期计算的工具。
此包包含两个计算器,FastForwarder 和 Rewinder,以及可以与它们一起使用的过滤器集。
FastForwarder 配置了一个天数(N)和一组回调,定义了什么 不是 工作日。一旦配置,提供起始日期,它将返回至少 N 个工作日后的第一个工作日。Rewinder 做同样的工作,只是时间方向相反。
传递给计算器的起始日期可以是 DateTime 或 DateTimeImmutable 及其子类。返回的值将是传入的副本,其时间戳已更新。
此库应遵循 PSRs 1、2 和 4,并需要 PHP 5.5 或更高版本(推荐使用 5.6)。5.6 是具有自动测试运行的最旧运行时版本。
安装
通过 Composer
$ composer require iansltx/business-days
如果您不想使用 Composer,您可以直接从 GitHub 下载源代码压缩包,并使用 PSR-4 兼容的自动加载器加载它。如果您没有这样的自动加载器,请 require autoload.php
以获取适用于此库的自动加载器。
使用方法
过滤器
计算器(FastForwarder 和 Rewinder)评估过滤器函数/方法/闭包,以确定给定日期是否应归类为工作日。您可以直接提供一个闭包,或使用方便的方法快速组合一个过滤器。
方便的方法只是包装来自 StaticFilter 的函数或通过 FilterFactory 创建闭包。这两个过滤器实用程序类都可以独立使用来过滤 DateTime 对象。此外,这两个过滤器类提供了比 FastForwarder/Rewinder 上的方便方法暴露的更多过滤器,因此在从头开始重新构建过滤器定义之前请检查它们。
请注意,需要数字输入的过滤器需要进行内部检查,要求对所有参数进行显式的 int 转换。此外,虽然 skipWhen 过滤器在添加时执行参数和返回类型测试,但允许使用非闭包参数,因此您可以使用对象方法、实用函数或全局函数作为闭包外的过滤器。
让我们设置一个 FastForwarder,添加一些过滤器,并做一些计算...
use iansltx\BusinessDays\FilterFactory; use iansltx\BusinessDays\StaticFilter; // set up the instance with a day count $ff = new iansltx\BusinessDays\FastForwarder(10); // add a closure-based filter $ff->skipWhen(function (\DateTimeInterface $dt) { // return $dt->format('m') == 12 && $dt->format('d') == 25; }, 'christmas'); // define a closure from the filter factory, then pass it in $dayAfterChristmasFriday = FilterFactory::monthAndDayOnDayOfWeek(12, 26, 5); $ff->skipWhen($dayAfterChristmasFriday, 'day_after_christmas_friday'); // convenience method; saved to filter slot 'weekend' $ff->skipWhenWeekend(); // overwrites 'weekend' slot with an identical call $ff->skipWhen(['iansltx\BusinessDays\StaticFilter', 'isWeekend'], 'weekend'); // use some other convenience methods, this time pulling from FilterFactory and using method chaining $ff->skipWhenNthDayOfWeekOfMonth(3, 1, 2, 'presidents_day') // third Monday of February ->skipWhenNthDayOfWeekOfMonth(4, 4, 11, 'thanksgiving') // fourth Thursday of November ->skipWhenMonthAndDay(1, 1) // auto-named to md_1_1 since a filter name wasn't provided ->skipWhen([StaticFilter::class, 'isGoodFriday'], 'good_friday') ->skipWhen([StaticFilter::class, 'isEasterMonday'], 'easter_monday'); // calculate some dates echo $ff->exec(new \DateTime('2015-11-20 09:00:00'))->format('Y-m-d H:i:s'); // 2015-12-07 09:00:00 echo $ff->exec(new \DateTimeImmutable('2015-02-12 09:00:00'))->format('Y-m-d H:i:s'); // 2015-02-27 09:00:00
注意:分数天向上取整到下一个整数天;例如,2.5 天将视为 3。
导出/导入过滤器集
与给定计算器关联的过滤器列表可以通过 getSkipWhenFilters()
作为数组导出。此数组可以作为创建该计算类时的过滤器存储,因此只需要定义一次过滤器集。
关于此功能的几点说明
- 在构造之后添加的任何过滤器都不会传播到您从原始过滤器集中获取计算对象的计算对象。
- 在构造时传递过滤器集不会对其中包含的过滤器执行参数和返回类型测试。
有了这些,让我们将我们的过滤器复制到一个新的 Rewinder 中,正如其名称所暗示的,它朝相反的方向前进,并计算更多日期。
// you could also create a FastForwarder with a negative day count with the same effect $rw = new iansltx\BusinessDays\Rewinder(2, $ff->getSkipWhenFilters()); echo $rw->exec(new \DateTime('2015-02-10 09:00:00'))->format('Y-m-d H:i:s'); // 2015-02-06 09:00:00 echo $rw->exec(new \DateTime('2015-02-18 09:00:00'))->format('Y-m-d H:i:s'); // 2015-02-13 09:00:00
更多信息
有关过滤器参数等更多信息,请查看源代码。所有方法和类都有文档块。基于可调用的 skipWhen() 语法允许任意复杂地定义日期是否应跳过,如在 isEasterMonday 等更复杂的过滤器中可以看到。
测试
$ composer test
humbug.json
如果您想使用 Humbug 进行变异测试,则需要包含。目前,并非所有变异都被捕获;欢迎提交 PR 来帮助解决这个问题。 composer test
仅运行 PHPUnit 测试。
贡献
有关详细信息,请参阅 CONTRIBUTING。欢迎贡献额外的静态过滤器/过滤器工厂!
安全性
如果您发现任何与安全相关的问题,请通过电子邮件 iansltx@gmail.com 联系,而不是使用问题跟踪器。
致谢
许可
此库使用 BSD 2 条款许可。有关更多信息,请参阅 许可文件。