org_heigl / 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
检查给定日期是否为节假日 - 本地化
这个库允许您将一天与一个或多个日历进行比较,以查看给定日期是否为节假日。
这也包括“命名日”,这些日不一定“免费”,但具有特殊名称,如“圣灰星期三”。
安装
holidayChecker最好通过composer安装
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包含命名日的名称。
您还可以使用2字母的ISO 3166-1或4字母的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文件中检索的,因此您可以无问题地添加自己的假期。它们需要与模式文件相匹配,并且在模式检查之前,任何XInclude语句都会被执行。
然后,您可以使用createIteratorFromXmlFile
方法从您的文件中加载假期。
如果您认为XML文件可能对他人有用,您应该考虑贡献回社区,在这里提交一个PullRequest,或者将它们附加到您开启的问题中。
我们将非常感激!
比较
Yasumi
PHP生态系统中的主要其他库也是提供假期日历的Yasumi库。这两个库之间有一些差异,我想在这里强调。
主要区别在于Yasumi是一个纯程序库。假期及其规则以代码形式记录。通过添加新日历或根据特定要求修改现有日历来扩展库需要实际的编码工作。与此相反,在这个库中,实际数据以XML文件的形式提供。添加新日历或扩展现有日历是否比进行PHP编程更容易,由用户自行决定。
此外,Yasumi使用基于非格里历(如伊斯兰、犹太或基于月球的节日)的假期的预计算日期。而另一方面,这个库根据特定日历中的日期定义假期。为此,我们使用底层的ICU日历,这使得我们能够根据佛教、中国、科普特、埃塞俄比亚、希伯来、印度、伊斯兰、日本和波斯日历声明假期。对于伊斯兰日历,我们支持不同的日计算版本,主要是天文日历和民用日历。这两个库在基于实际观察的日历系统(如沙特阿拉伯使用的伊斯兰日历)使用时都会遇到问题。因为这些日历是基于视觉观察的,所以不能预先计算,因此不能与预先计算库一起使用。
鉴于这种差异,Yasumi库目前仅允许使用1949年至2050年之间的日期,而此库在使用日期范围上没有限制。
另一个差异是要求。虽然Yasumi只需要PHP 7.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'), );