hnesk/todate

用于日期表达式的简单易用的DSL

v1.0.2 2021-03-12 23:28 UTC

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]);

使用逻辑运算符组合条件

所有条件都可以使用ANDORNOT组合成复杂的日期条件。

\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