wengooooo / holidaychecker
检查节假日 - 本地化
该软件包的官方仓库似乎已不存在,因此软件包已被冻结。
Requires
- php: ^7.3|^8.0
- ext-dom: *
- ext-intl: *
- org_heigl/dateintervalcomparator: ^1.0
Requires (Dev)
- mockery/mockery: ^1.0
- phpunit/phpunit: ^8.0 || ^9.0
- slevomat/coding-standard: ^6.4 || ^7.0 || ^8.0
- squizlabs/php_codesniffer: ^3.0
README
检查给定日期是否为节假日 - 本地化
该库允许您将某一天与一个或多个日历进行比较,以查看该天是否为节假日。
这还包括“命名日”,这些日可能不是“免费”的,但有特殊的名称,如“圣周四”。
安装
建议使用 composer 安装 holidayChecker
composer require org_heigl/holidaychecker
使用方法
简单用法
$factory = new HolidayIteratorFactory();
$iterator = $factory->createIteratorFromXmlFile('path/to/a/holiday/file.xml');
$checker = new Holidaychecker($iterator);
$result = $checker->check(new \DateTime());
// $result will be an instance of Org_Heigl\HolidayChecker\Holiday
$result 有 3 个方法
- isHoliday 当根据当地法律该天为假日时返回 `true`。否则返回 `false`
- isNamed 当该天有特殊名称但不是假日时返回 `true`
- getName 包含命名日的名称
您还可以使用两个字母的 ISO 3166-1 或四个字母的 ISO 3166-2 码获取 `
HolidayIterator`。当有不同语言变体可用时,您可以通过在 ISO 3166-码之前添加 ISO 639-1 语言码 来获取它们
// Get the holidays for mainland france
$iterator = $factory->createIteratorFromIso3166('FR');
// Get the holidays for the french overseas-department La Reunion
$iterator = $factory->createIteratorFromIso3166('FR-RE');
// Get the dutch holidays for belgium
$iterator = $factory->createIteratorFromIso3166('fr_BE');
可用的国家
目前这些国家可用
- 德国(所有联邦州,德语)
- 卢森堡(德语、法语和卢森堡语)
- 比利时(佛兰德语和法语)
- 荷兰(荷兰语)
- 法国(大陆和海外,适应阿尔萨斯/洛林,法语)
- 英国(岛屿、威尔士、苏格兰、北爱尔兰和英格兰,英语)
- 芬兰
- 俄罗斯
- 希腊
- 土耳其
- 南非(英语)
- 爱尔兰(英语和爱尔兰语)
- 西班牙(所有省份,西班牙语)
- 葡萄牙(大陆、马德拉群岛和亚速群岛,葡萄牙语)
- 丹麦(丹麦语)
- 瑞典(瑞典语)
- 挪威(博克马尔语)
- 波兰(波兰语)
- 奥地利(德语)
- 意大利(意大利语)
- 加拿大(法语和英语)
- 美国(仅联邦假日 - 英语)
- 巴西(巴西葡萄牙语)
- 日本(需要更好的方式来处理春分)
- 中国(需要更好的方式来处理二十四节气)
- 阿富汗(英语)
- 阿尔巴尼亚(阿尔巴尼亚语)
- 阿尔及利亚(英语)
- 安道尔(所有教区)
- 安哥拉
- 安提瓜和巴布达
- 阿根廷
- 亚美尼亚
- 澳大利亚包括圣诞岛、科科斯(基林)群岛和诺福克岛
- 阿塞拜疆
- 巴哈马
- 巴林
- 孟加拉国(缺少印度教和佛教节日的计算)
- 巴巴多斯
- 白俄罗斯
- 伯利兹
- 贝宁
- 百慕大
- 不丹
- 玻利维亚
- 波斯尼亚和黑塞哥维那
- 博茨瓦纳
- 文莱
- 布基纳法索
- 布隆迪
- 保加利亚
- 柬埔寨
- 喀麦隆
- 佛得角
- 中非共和国
- 墨西哥
- 乍得
- 智利
- 科特迪瓦
- 哥伦比亚
- 科摩罗
- 刚果民主共和国
- 刚果共和国
- 哥斯达黎加
- 克罗地亚
- 古巴
- 塞浦路斯
- 捷克共和国
- 瑞士
但这个列表还在不断扩展。
扩展
目前并非所有国家的节假日都可用。我们正在努力解决这个问题,但您可能会发现您需要的国家正好缺失。
由于假期是从XML文件中检索的,因此您可以无问题地添加自己的假期。它们需要与Schema文件相匹配,并且在检查模式之前,任何XInclude语句都会被执行。
然后,您可以使用`
createIteratorFromXmlFile`
方法从您的文件中加载假期。
如果您认为XML文件对其他人可能有用,您应该考虑做出贡献,在此处打开PullRequest,或者将它们附加到您打开的问题中。
我们会非常感激!
比较
Yasumi
在PHP生态系统中的主要其他库是Yasumi库,它也提供假期日历。不过,这两个库之间有一些差异,我在这里想强调一下。
主要区别在于,Yasumi是一个纯编程库。假期及其规则在代码中记录。通过添加新日历或根据特定要求修改现有日历来扩展库需要实际编码。与此相反,在这个库中,实际数据以XML文件的形式提供。添加新日历或扩展现有日历需要创建一个新的或修改现有的XML文件。是否比进行PHP编程更容易,由用户自行决定。
此外,Yasumi使用基于非公历的假期(如伊斯兰教、犹太教或基于阴历的假期)的预先计算的日期。而在这个库中,我们根据特定日历中的日期来定义假期。为此,我们在底层使用ICUs日历,这使得我们可以根据佛教、中国、科普特、埃塞俄比亚、希伯来、印度、伊斯兰、日本和波斯日历声明假期。对于伊斯兰历,我们支持不同的日计算版本,主要是天文历和平民历。这两个库在基于实际观察的系统(如沙特阿拉伯使用的伊斯兰历)的日历系统上都有问题。因为这些日历是基于视觉观察的,所以不能预先计算,因此不能与预先计算的库一起使用。
鉴于这种差异,Yasumi库目前只允许使用1949年至2050年之间的日期,而此库的使用日期范围是自由的。
另一个区别是要求。虽然Yasumi只需要PHP7.4或更低版本以及可用的JSON扩展,但此库还需要DOM扩展(XML)以及INTL扩展,因为我们使用它来根据不同的日历系统计算假期。此库还要求一个用于比较日期间隔的库,该库用于计算复活节日期的计算。
Calendarific
Calendarific是一家SaaS提供商,通过API提供全球银行假期和观察日。
他们目前支持全球所有国家。他们的API可以按国家和年份查询假期信息。可以只获取国家的一个子区域(如美国的州或瑞士的州)的信息。您还可以通过提供日期和月份以及年份来检查特定的某一天。
由于API的定价限制了每月的API调用次数,因此按日调用API可能不是最好的主意。此外,API提供有关本地、国家或宗教假期以及观察日的信息(在某个地区可能是国家或地区假期,而在另一个地区可能是地方或国家假期)。遗憾的是,似乎无法在单个请求中获取仅限于地区和国家的地方和国家假期。要么是所有这些,要么只有一个。而且,“观察”类型相当啰嗦(它包含很多可能或可能没有相关性的特殊日期 - 如可能通过单独的库计算得更好的天文观测)
因此,作为消费者,当想要获取有关某个地区是否为假日的信息时,需要做大量工作才能获取实际所需的数据。
它有它的作用,而且可以随时使用。但需要支付费用。
缺少的功能
工作日
有些人询问是否可以计算工作日。虽然这似乎是一个很好的功能,但我决定不在库中实现它,因为工作日非常特定于行业领域。尽管普遍认为“工作日”是周一至周六,不包括公共假日,但这并不总是正确的,也不适用于所有地方。因此,根据您的业务领域,工作日可能只有周一至周五,并且并非所有公共假日都被排除在外,而只是排除了一部分。例如,英国的银行假日只是针对银行的假日,但对于许多其他企业来说,它们意味着正常营业。或者也许不是,这取决于许多不同的因素。
为了避免给人带来错误的期望,并使用可能会很快反噬的魔法,我决定不在库中实现这一功能,而将其留给您的业务逻辑。
为了给您一个这种功能可能看起来怎样的概念,我编写了一个示例,说明大部分所需代码实际上是业务案例相关或用于设置的。只有三行与这个库相关。因此,在这个库中为它创建一个专门的类似乎没有意义。
<?php
/**
* Copyright Andreas Heigl <andreas@heigl.org>
*
* Licenses under the MIT-license. For details see the included file LICENSE.md
*/
use Org_Heigl\Holidaychecker\Holidaychecker;
use Org_Heigl\Holidaychecker\HolidayIteratorFactory;
$factory = new HolidayIteratorFactory();
$iterator = $factory->createIteratorFromISO3166('DE');
$checker = new Holidaychecker($iterator);
$startDate = new DateTimeImmutable('2022-10-10');
$endDate = new DateTimeImmutable('2022-10-31');
$dateIterator = new DatePeriod(
$startDate,
new DateInterval('P1D'),
$endDate
);
$numberOfBusinessDays = 0;
foreach ($dateIterator as $date) {
if ($checker->check($date)->isHoliday()) {
continue;
}
// Your business-Logic here
// This is where the magic actually happens.
// Whether you count only sundays.
// Or saturdays AND sundays or whatever else your general days off are!
$numberOfBusinessDays++;
}
echo sprintf(
'There are %1$d business-days between %2$s and %3$s',
$numberOfBusinessDays,
$startDate->format('d.m.Y'),
$endDate->format('d.m.Y'),
);