hnesk / todate
用于日期表达式的简单易用的DSL
v1.0.2
2021-03-12 23:28 UTC
Requires
- php: >=7.0.0
- ext-calendar: *
- smuuf/php-peg: ~2.0
Requires (Dev)
- phpunit/phpunit: ~9.0
This package is auto-updated.
Last update: 2024-09-13 07:26:05 UTC
README
一个PHP日期表达式库,带有相应的领域特定语言(DSL)
将日期条件描述为字符串(DSL)
此库包含一个DSL(领域特定语言),用于将复杂的日期场景描述为简单的字符串。这些DSL表达式被解析为表达式树,可以用于评估任何给定的日期。
听起来很复杂?其实并不复杂。
想象一下,你的垃圾每周一的第一天被清理。你将如何向机器传达这一事实?
use ToDate\ToDate; $garbageTime = 'DayOfWeekOfMonth=1MON'; foreach (ToDate::conditionalIterator('2021-01-01', '2021-12-31', $garbageTime) as $garbageDay) { echo $garbageDay->format('d.m.Y, l') . PHP_EOL; }
每个月的第一天和第三天星期一呢?
$garbageTime = 'DayOfWeekOfMonth=1,3MON';
每个月的第二天和最后一天星期一呢?(使用Python中负数的概念,从最后一天开始计数)
$garbageTime = 'DayOfWeekOfMonth=2,-1MON';
好吧,让我们假设每周一,但不是复活节星期一(常量Easter
表示复活节星期日)
$garbageTime = 'DayOfWeek=MON AND(NOT(Date=Easter+1)';
或者圣灵降临节星期一(复活节星期日后50天)、独立日或圣诞节呢?
$garbageTime = 'DayOfWeek=MON AND NOT(Date=Easter+1 OR Date=Easter+50 OR DayAndMonth=04/07 OR DayAndMonth=25/12 OR DayAndMonth=26/12)';
ToDate/Condition命名空间中的所有日期条件都可以使用相应的DSL字符串语法创建
DSL构建块
所有这些条件都映射到单个\ToDate\Condition\AbstractDateCondition
实例。
日期
仅一个固定日期,例如仅在2021年独立日
\ToDate\ToDate::condition('Date=2021-07-04') == new \ToDate\Condition\DateCondition(new DateTime('2021-07-04'));
基于复活节的日期条件
每个圣灵降临节星期日
\ToDate\ToDate::condition('Date=Easter+49') == new \ToDate\Condition\EasterBasedCondition(\ToDate\Condition\EasterBasedCondition::WHIT_SUNDAY /* or 49 */);
日期取模
从2021年3月12日起每隔2周(14天)
\ToDate\ToDate::condition('DateModule=2021-03-12%14') == new \ToDate\Condition\DateModuloOffsetCondition(new DateTime('2021-03-12'), 14);
日期和月份
每个独立日
\ToDate\ToDate::condition('DayAndMonth=4/7') == new \ToDate\Condition\DayAndMonthCondition(4,7);
日期
每个月的第一天和15天
\ToDate\ToDate::condition('DayOfMonth=1,15') == new \ToDate\Condition\DayOfMonthCondition([1,15]);
或者每个月的第一天到第九天
\ToDate\ToDate::condition('DayOfMonth=1-9') == new \ToDate\Condition\DayOfMonthCondition([1,2,3,4,5,6,7,8,9]);
星期几
每个星期六和星期日
\ToDate\ToDate::condition('DayOfWeek=SAT,SUN') == new \ToDate\Condition\DayOfWeekCondition([\ToDate\Condition\DayOfWeekCondition::SAT, \ToDate\Condition\DayOfWeekCondition::SUN]);
星期几和月份
每个月的第一天和第三天星期一
\ToDate\ToDate::condition('DayOfWeekOfMonth=1,3MON') == new \ToDate\Condition\DayOfWeekOfMonthCondition([1,3], \ToDate\Condition\DayOfWeekCondition::MON);
每个月的第二天和最后一天星期一
\ToDate\ToDate::condition('DayOfWeekOfMonth=2,-1MON') == new \ToDate\Condition\DayOfWeekOfMonthCondition([1,3], \ToDate\Condition\DayOfWeekCondition::MON);
月份
在夏季
\ToDate\ToDate::condition('Month=3-10') == new \ToDate\Condition\MonthCondition([3,4,5,6,7,8,9,10]);
年份
新冠疫情年份
\ToDate\ToDate::condition('Year=2020,2021') == new \ToDate\Condition\YearCondition([2020,2021]);
使用逻辑运算符组合条件
所有条件都可以使用AND
、OR
和NOT
组合成复杂的日期条件。
\ToDate\ToDate::condition('DayOfWeek=MON AND NOT(Date=Easter+1)') == new \ToDate\Condition\IntersectionCondition( new \ToDate\Condition\DayOfWeekCondition(\ToDate\Condition\DayOfWeekCondition::MON), new \ToDate\Condition\NotCondition(new \ToDate\Condition\EasterBasedCondition(1)) );
示例
另请参阅可执行示例
use ToDate\ToDate; $secondOrLastSaturday = ToDate::condition('DayOfWeekOfMonth = 2,-1SAT'); var_dump($secondOrLastSaturday->contains(new \DateTime('2014-11-29'))); # bool(true) var_dump($secondOrLastSaturday->contains(new \DateTime('2014-11-09'))); # bool(false) $everySecondAndLastSaturydayIn2021 = ToDate::conditionalIterator('2021-01-01', '2021-12-31', $secondOrLastSaturday); foreach ($everySecondAndLastSaturydayIn2021 as $saturday) { echo $saturday->format('d.m.Y, l') . PHP_EOL; } # 09.01.2021, Saturday # 30.01.2021, Saturday # 13.02.2021, Saturday # ... # 11.12.2021, Saturday # 25.12.2021, Saturday /* All german holidays 2021 in one simple string! */ $germanHolidays = 'DayAndMonth = 1/1 OR Date = Easter-2 OR Date = Easter+1 OR DayAndMonth = 1/5 OR Date = Easter+39 OR Date = Easter+50 OR Date = Easter+60 OR DayAndMonth = 3/10 OR DayAndMonth = 1/11 OR DayAndMonth = 25/12 OR DayAndMonth = 26/12'; $holidays = ToDate::conditionalIterator('2021-01-01', '2021-12-31' ,$germanHolidays); foreach ($holidays as $holiday) { echo $holiday->format('d.m.Y, l') . PHP_EOL; } # 01.01.2021, Friday # 02.04.2021, Friday # 05.04.2021, Monday # 01.05.2021, Saturday # 13.05.2021, Thursday # 24.05.2021, Monday # 03.06.2021, Thursday # 03.10.2021, Sunday # 01.11.2021, Monday # 25.12.2021, Saturday # 26.12.2021, Sunday