madison-solutions / just-date
处理不带任何时间信息的日期的PHP库
Requires
- php: ^8.1
- ext-json: *
Requires (Dev)
- laravel/pint: ^1.17
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.3
README
PHP库,用于处理不带任何时间信息的日期,以及不带任何日期信息的时间
有多个出色的PHP库用于处理DateTime对象。但有时你只需要处理DateTime对象的日期部分或时间部分。
例如,酒店预订系统可能只关心客人的入住日期 - 而到达的确切时间并不重要。在这种情况下,与一天中的时间相关的一切功能都只是障碍,使得比较和相等检查变得尴尬。时区和夏令时等附加的复杂性进一步使问题复杂化。
该库旨在使处理日期部分或时间部分变得简单。
下面是功能快速指南和一些示例,或者查看此处API参考。
注意,以下说明针对版本2 - 查看从版本1迁移的帮助迁移指南。
安装
composer require madison-solutions/just-date
JustDate
表示不带时间信息的一个单独的日期
基本用法
use MadisonSolutions\JustDate\JustDate; $date = JustDate::make(2019, 4, 21); (string) $date; // 2019-04-21 $date->format('D F jS Y'); // Sun April 21st 2019 $date->year; // 2019 $date->month; // 4 $date->day; // 21 $date->day_of_week; // DayOfWeek::Sunday $data->day_of_week->value; // 0 $date2 = JustDate::fromYmd('2019-04-22'); $date->isBefore($date2); // true
忽略时间
use MadisonSolutions\JustDate\JustDate; $t1 = new DateTime('2019-04-21 16:23:12', new DateTimeZone('Australia/Sydney')); $t1->format('r'); // Sun, 21 Apr 2019 16:23:12 +1000 $d1 - JustDate::fromDateTime($t1); $d1->format('r'); // Wed, 24 Apr 2019 00:00:00 +0000 // Different time, different timezone, but the date part is the same $t2 = new DateTime('2019-04-21 19:05:47', new DateTimeZone('Europe/London')); $d2 = JustDate::fromDateTime($t2); $d1->isSameAs($d2); // true
今天的日期
use MadisonSolutions\JustDate\JustDate; // The current date, in the local timezone $today = JustDate::today(); // What date is is right now in Denver? $today_in_denver = JustDate::today(new DateTimeZone('America/Denver'));
遍历日历
use MadisonSolutions\JustDate\JustDate; $d1 = JustDate::make(2019, 04, 21); $d2 = $d1->nextDay(); (string) $d2; // 2019-04-22
注意,JustDate对象是不可变的 - nextDay()
和所有其他类似方法返回新的JustDate实例!
(string) $d1->prevDay(); // 2019-04-20 (string) $d1->addDays(3); // 2019-04-24 (string) $d1->startOfMonth(); // 2019-04-01 (string) $d1->endOfMonth(); // 2019-04-30 // What day was it on this day 2 years ago? JustDate::make($d1->year - 2, $d1->month, $d1->day)->format('l'); // Friday // Find the previous Wednesday $date = $d1; while (! $date->isWednesday()) { $date = $date->prevDay(); } $date->format('D F jS Y'); // Wed April 17th 2019 // How many days is it until the start of the next month? JustDate::difference($d1, $d1->endOfMonth()->nextDay()) // 10
工作日
// Add a certain number of 'working' days $holidays = new DateSet(...[ JustDate::make(2023, 12, 25), // Christmas JustDate::make(2023, 12, 26), // Boxing Day JustDate::make(2024, 1, 1), // New Year's Day ]); $order_date = JustDate::make(2023, 12, 28); // Delivery in 3 working days // 29th Dec is Friday (a working day), 30 & 31 are weekend, 1st is holiday, 2nd and 3rd are next 2 working days $delivery_date = $order_date->addWorkingDays(3, $holidays); // Wed 3rd Jan 2024
DateRange
表示从某个开始日期到某个结束日期之间的日期范围(不带时间信息)。
use MadisonSolutions\JustDate\DateRange; use MadisonSolutions\JustDate\JustDate; $start = JustDate::make(2019, 04, 21); $end = $d1->addDays(4); $range = DateRange::make($start, $end); (string) $range; // 2019-04-21 to 2019-04-25 (string) $range->start; // 2019-04-21 (string) $range->end; // 2019-04-25 $range->includes(JustDate::make(2019, 04, 22)); // true // alternatively create from strings $range = DateRange::fromYmd('2019-04-21', '2019-04-25');
注意,你不能创建一个起始日期在结束日期之后的范围
$illegal_range = DateRange::make(JustDate::fromYmd('2019-04-22'), JustDate::fromYmd('2019-04-20')); // Throws an \InvalidArgumentException
如果你不确定你的两个日期哪个先,你可以使用eitherWayRound()
。
$range = DateRange::eitherWayRound(JustDate::fromYmd('2019-04-22'), JustDate::fromYmd('2019-04-20')); $range->start; // 2019-04-20 $range->end; // 2019-04-22
两个范围的交集
$range2 = DateRange::fromYmd('2019-04-18', '2019-04-23'); (string) DateRange::intersection($range, $range2); // 2019-04-21 to 2019-04-23 $range3 = DateRange::fromYmd('2019-04-18', '2019-04-19'); DateRange::intersection($range, $range3); // null - they don't intersect
遍历范围
foreach ($range->each() as $date) { echo $date->format('d') . ","; } // 21,22,23,24,25, foreach ($range->each(backwards: true) as $date) { echo $date->format('d') . ","; } // 25,24,23,22,21,
日期范围的长度
当谈论日期范围的“长度”时,有一个关于这个含义的不确定性。
例如,如果你有一个日期范围,其中$start
是周二4号,而$end
是周一8号,如以下图表所示,那么这个范围的“长度”应该是什么?
有两种相当合理但不同的定义。
你可以计算包含在范围内的天数(包括起始和结束日期)。在上面的例子中,答案将是5。这也可以被视为从起始日期的第一秒到结束日期的最后一秒的长度,按天计算。根据这种定义,最小可能的DateRange,其中起始和结束日期是同一天,长度为1。
或者你可以通过从结束日期减去起始日期来定义长度。在上面的例子中,答案是8 - 4 = 4。这也可以被视为从起始日期的中点到结束日期的中点的天数,或者作为从起始日期到结束日期之间的夜晚数。根据这种定义,最小可能的DateRange,其中起始和结束日期是同一天,长度为0。
DateRange类提供了这两种选项 - 第一个可以通过$range->outer_length
访问,第二个可以通过$range->inner_length
访问。
$range = DateRange::fromYmd('2019-04-04', '2019-04-08'); $range->inner_length; // 4 $range->outer_length; // 5
JustTime
表示一个没有日期信息的时刻。
use MadisonSolutions\JustDate\JustTime; $time = JustTime::make(17, 45, 30); (string) $time; // 17:45:30 $time->format('g:ia'); // 5:45pm $time->hours; // 17 $time->minutes; // 45 $time->seconds; // 30 $time->since_midnight; // 63930 $time2 = JustTime::fromHis('17:55:00'); $time->isBefore($time2); // true $time3 = JustTime::fromSecondsSinceMidnight(125); // 00:02:05
忽略日期信息。
移除日期部分以及时区。如果在格式字符串中使用日期参数,日期将是1970年1月1日(Unix纪元)。
use MadisonSolutions\JustDate\JustTime; $t1 = new DateTime('2019-04-21 16:23:12', new DateTimeZone('Australia/Sydney')); $t1->format('r'); // Sun, 21 Apr 2019 16:23:12 +1000 $time1 - JustTime::fromDateTime($t1); $time1->format('r'); // Thu, 01 Jan 1970 16:23:12 +0000 // Different date, different timezone, but the time part is the same $t2 = new DateTime('2018-10-06 16:23:12', new DateTimeZone('Europe/London')); $time2 = JustTime::fromDateTime($t2); $time1->isSameAs($time2); // true
当前时间。
use MadisonSolutions\JustDate\JustTime; // The current time, in the local timezone $now = JustTime::now(); // What time is is right now in Denver? $time_now_in_denver = JustTime::now(new DateTimeZone('America/Denver'));
遍历时钟。
注意:JustTime 对象是 不可变 的 - addTime()
返回新的 JustTime 实例!
use MadisonSolutions\JustDate\JustTime; $t1 = JustTime::make(12, 0, 0); $t2 = $t1->addTime(2, 30, 10); (string) $t2; // '14:30:10' $t3 = $t1->addTime(14, 0, 0); (string) $t3; // '02:00:00' $t4 = $t1->addTime(0, 0, -1); (string) $t4; // '11:59:59'
四舍五入到特定间隔。
use MadisonSolutions\JustDate\JustTime; $t1 = JustTime::make(12, 47, 10); // round to nearest minute $t2 = $t1->round(60); // 12:47:00 // round to nearest quarter of an hour $t3 = $t1->round(15 * 60); // 12:45:00
DateSet 和 MutableDateSet
表示一组日期(不一定是一个连续的范围)。MutableDateSet 可以添加或删除日期,而 DateSet 在创建后不能更改。
use MadisonSolutions\JustDate\DateSet; use MadisonSolutions\JustDate\MutuableDateSet; // Create a DateSet from any number of JustDate or DateRange objects (or other DateSet objects) $set = new DateSet(JustDate::fromYmd('2023-11-17'), DateRange::fromYmd('2023-10-01', '2023-10-10'), JustDate::fromYmd('2023-10-05')); // Dates in the sets are automatically de-duplicated and sorted (string) $set; // '2023-10-01 to 2023-10-10, 2023-11-17' $set->includes('2023-10-11'); // false $mset = new MutableDateSet(); $mset->isEmpty(); // true $mset->add(JustDate::fromYmd('2023-11-17')); (string) $mset; // '2023-11-17' $mset->add(DateRange::fromYmd('2023-10-01', '2023-10-10')); (string) $mset; // '2023-10-01 to 2023-10-10, 2023-11-17'
组合/比较 DateSets
$a = new DateSet(DateRange::fromYmd('2023-11-05', '2023-11-09')); $b = new DateSet(DateRange::fromYmd('2023-11-08', '2023-11-12')); DateSet::union($a, $b); // 2023-11-05 to 2023-11-12 DateSet::intersection($a, $b); // 2023-11-08 to 2023-11-09 $a->subtract($b); // 2023-11-05 to 2023-11-07 $b->subtract($a); // 2023-11-10 to 2023-11-12
DateSet 和 MutableDateSet 的 contains($other)
方法可以用来与其他对象比较,以测试它们是否包含另一个对象中的所有日期。其他对象不必是相同类型,它可以是 JustDate、DateRange、DateSet 或 MutableDateSet(或实现 DateRangeList 接口的任何其他对象)。
$jan_and_march = new DateSet(DateRange::fromYmd('2024-01-01',' 2024-01-31'), DateRange::fromYmd('2024-03-01', '2024-03-31')); $jan_and_march->contains(DateRange::fromYmd('2024-01-10', '2024-01-20')); // true $jan_and_march->contains(DateSet::fromString('2024-01-01, 2024-01-17, 2024-03-05')); // true $jan_and_march->contains(JustDate::fromYmd('2024-02-10')); // false
DateSet 和 MutableDateSet 的 isSameAs($other)
方法可以用来与其他对象比较,以测试它们是否包含 完全相同 的日期集合。同样,其他对象不必是相同类型。
$set = new DateSet(JustDate::fromYmd('2024-08-01'), JustDate::fromYmd('2024-08-02'), JustDate::fromYmd('2024-08-03')); $set->isSameAs(DateRange::fromYmd('2024-08-01', '2024-08-03')); // true - $set contains the exact same 3 dates that are in the DateRange
遍历 DateSet
您可以选择遍历集合中的连续范围,或遍历单个日期。
$set = new DateSet(JustDate::fromYmd('2023-10-17'), DateRange::fromYmd('2023-10-20', '2023-10-25')); foreach ($range->eachRange() as $range) { echo $range->start->format('d') . '-' . $range->end->format('d') . ", "; } // 17-17, 20-25, foreach ($range->eachDate() as $date) { echo $date->format('d') . ","; } // 17,20,21,22,23,24,25,