处理不带任何时间信息的日期的PHP库

v2.2.1 2024-08-05 06:47 UTC

This package is auto-updated.

Last update: 2024-09-05 07:02:44 UTC


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,