stubbles / date
简化日期和日期范围的处理。
Requires
- php: ^8.2
- ext-ctype: *
Requires (Dev)
- bovigo/assert: ^8.0
- phpunit/phpunit: ^10.5
- stubbles/reflect: ^10.0
Suggests
- bovigo/assert: To use predicates when asserting dates with stubbles\date\assert\equalsDate()
README
以不可变的方式处理日期和日期范围,使用美观的API。
构建状态
安装
stubbles/date 以 Composer 包的形式分发。要将它作为你的包的依赖项安装,请使用以下命令
composer require "stubbles/date": "^9.0"
需求
stubbles/date 至少需要 PHP 8.2。
简介
这个库中的类起源于 PHP 的面向对象日期/时间处理类不可变的时代。在此期间,PHP 中已经添加了它们的不可变版本,但我们更喜欢这里类的 API,因为它们在使用它们的代码中导致了更好的语法。
底层实现使用 PHP 的面向对象日期/时间处理类,但将它们抽象化,使得 stubbles/date 实例是不可变的。对日期的任何更改都会导致一个新实例。尽管日期类公开了底层句柄,但用户将只收到它的克隆,因此修改这样的句柄不会改变从该句柄获取的日期实例。
stubbles\date\Date
请注意,这个类不仅覆盖了一个日期,还包括了一个具体的时间点。每个实例还有一个时间部分。如果您只对具体的一天感兴趣,请使用 stubbles\date\span\Day
(见下文)。
创建一个新实例
在创建新的日期实例时,有不同方式设置实际日期
- 整数,解释为时间戳:
new Date(1187872547)
- 字符串,解析为日期:
new Date('2007-01-01 01:00:00 Europe/Berlin')
\DateTime
对象,将直接使用:new Date(new \DateTime())
- 没有参数,创建代表当前时间的日期:
new Date()
,等同于Date::now()
构造函数的第二个参数是可选的时区。时区分配遵循以下规则
- 如果时间以字符串形式给出且包含可解析的时区标识符,则使用该标识符。
- 如果无法确定时区,则使用第二个构造函数参数给出的时区。
- 如果未给出第二个参数,则使用系统的默认时区。
自由类型提示
如果您有一个接受 stubbles\date\Date
实例的方法,您可以选择在您接受的内容上更加宽容。您的函数可以不针对具体类型进行类型提示,而是将提供的值转换为实例
/** * does something cool * * @param int|string|stubbles\date\Date $date */ function doSomething($date) { $date = Date::castFrom($date); // now do something with $date, which is an instance of stubbles\date\Date }
Date::castFrom();
接受四种不同的值类型
- 整数,解释为 Unix 时间戳:
Date:castFrom(1187872547)
- 字符串,解析为日期:
Date:castFrom('2007-01-01 01:00:00 Europe/Berlin')
\DateTime
对象:Date:castFrom(new \DateTime())
stubbles\date\Date
的实例
stubbles\date\Date
的实例将始终以原样返回,其他允许的值将导致创建一个 stubbles\date\Date
实例。传递任何其他值将导致抛出 \InvalidArgumentException
。
更改日期
要更改日期,可以调用 Date::change()
方法。这将返回一个 stubbles\date\DateModifier
实例,它提供了多种不同的方法来更改日期和/或时间。所有更改都将导致创建一个新的 stubbles\date\Date
实例,原始调用 Date::change()
的实例保持不变
$currentDate = Date::now(); // create new date with current time but 48 hours ago, this will not change $currentDate $newDate = $currentDate->change()->byHours(-48);
以下是 stubbles\date\DateModifier
提供的列表方法
to($target)
: 使用strtotime()
函数接受相对格式改变日期,详见strtotime()timeTo($time)
: 保持日期(即日、月、年),但将时间改为给定值,格式必须为HH:mm:sscreateDateWithNewTime($hour, $minute, $second)
: 与上述功能相同,但具有所有值的单独参数timeToStartOfDay()
:timeTo('00:00:00')
的别名timeToEndOfDay()
:timeTo('23:59:59')
的别名hourTo($hour)
: 保持日、月、年、分钟和秒,但将小时改为给定值byHours($hours)
: 将给定的小时数添加到当前日期和时间。负值将减去小时数minuteTo($minute)
: 保持日、月、年、小时和秒,但将分钟改为给定值byMinutes($minutes)
: 将给定分钟的分钟数添加到当前日期和时间。负值将减去分钟数。secondTo($second)
: 保持日、月、年、小时和分钟,但将秒改为给定值bySeconds($seconds)
: 将给定秒数的秒数添加到当前日期和时间。负值将减去秒数。dateTo($date)
: 改变日期但保持时间,给定日期必须是格式YYYY-MM-DDyearTo($year)
: 保持日、月、小时、分钟和秒,但将年改为给定值byYears($years)
: 将给定年数添加到当前日期和时间。负值将减去年数。monthTo($month)
: 保持日、年、小时、分钟和秒,但将月改为给定值byMonths($months)
: 将给定月数添加到当前日期和时间。负值将减去月数。dayTo($day)
: 保持月、年、小时、分钟和秒,但将日改为给定值byDays($days)
: 将给定日数添加到当前日期和时间。负值将减去日数。
日期比较
stubbles\date\Date
的实例可以相互比较
$date = Date::now(); if ($date->isBefore('2017-01-01 00:00:00')) { // execute when current date is before 2017 }
$date = Date::now(); if ($date->isAfter('2017-01-01 00:00:00')) { // execute when current date is after beginning of 2017 }
比较基于Unix时间戳。
isBefore()
和isAfter()
接受Date::castFrom()
接受的所有值,见上文。
日期格式化
可以通过格式化将日期显示为字符串
echo 'Current date and time in system timezone: ' . Date::now()->format('Y-m-d H:i:s') . PHP_EOL; echo 'Current date and time in timezone Europe/Berlin: ' . Date::now()->format('Y-m-d H:i:s', new TimeZone('Europe/Berlin')) . PHP_EOL;
当实例被转换为字符串时,输出格式将为Y-m-d H:i:sO。
日期范围
有时需要不覆盖特定日期,而是覆盖两个时间点之间的范围。最值得注意的是这些是诸如单日、月份、周甚至年份的事物。由于始终携带此类范围的起始点和结束点是不切实际的,stubbles/date提供了stubbles\date\span\Datespan
接口和不同的实现。
每个日期范围的方法
start()
: 返回范围的精确起始点startsBefore($date)
: 检查日期范围是否在给定点之前开始startsAfter($date)
: 检查日期范围是否在给定点之后开始end()
: 返回范围的精确结束点endsBefore($date)
: 检查日期范围是否在给定点之前结束endsAfter($date)
: 检查日期范围是否在给定点之后结束formatStart($format, TimeZone $timeZone = null)
: 以给定格式格式化起始点formatEnd($format, TimeZone $timeZone = null)
: 以给定格式格式化结束点amountOfDays()
: 返回日期范围覆盖的天数days()
: 返回一个迭代器,允许在日期范围内迭代每一天isInFuture()
: 根据当前日期和时间检查日期范围是否完全在未来containsDate($date)
: 检查给定的日期和时间是否包含在日期范围内
所有具有$date
参数的方法都接受Date::castFrom()
接受的所有值,见上文。
提供日期范围实现的列表
stubbles\dates\span\Day
覆盖整个一天,从00:00:00开始,到23:59:59结束。
// create without argument always points to current day $today = new Day(); // create with given date $another = new Day('2016-06-27'); // create day from given stubbles\date\Date instance $oneMore = new Day(new Date('2013-05-28')); // creates a new instance representing tomorrow $tomorrow = Day::tomorrow(); // creates a new instance representing yesterday $yesterday = Day::yesterday();
额外方法
next()
:创建一个代表表示日期后一天的新的实例before()
:创建一个代表表示日期前一天的新实例isToday()
:检查日期是否代表当前日期
stubbles\dates\span\Week
覆盖整个一周,从给定日期的00:00:00开始,到七天后23:59:59结束。
// create a week starting today $week1 = new Week(Date::now()); // create a week which starts tomorrow $week2 = new Week('tomorrow'); // create a week which represents the 5th calender week of 2016 $week3 = Week::fromString('2016-W05')
额外方法
number()
:返回周数
stubbles\dates\span\Month
覆盖一个月,从月初00:00:00开始,到月底23:59:59结束。
// creates instance representing the current month $currentMonth = new Month(); // creates instance with current month but in the year 2014-05 $currentMonthIn2015 = new Month(2015); // create instance representing June 2016 $exactMonth = new Month(2016, 6); // create instance representing month given as string, format must be YYYY-MM $otherMonth = Month::fromString('2016-07'); // creates instance representing the month before current month $lastMonth = Month::last(); // creates instance for current month execpt when today is the first day of a // month, the the instance represents the month before // ideally suited when creating reports, as most often the report created on the // first month of a day should be for the last month instead of for the current // month $reportingMonth = Month::currentOrLastWhenFirstDay()
额外方法
next()
:创建一个表示当前表示月份后一个月的实例before()
:创建一个表示当前表示月份前一个月的实例year()
:返回月份所在的年份isCurrentMonth()
:检查月份实例是否代表当前月份
stubbles\dates\span\Year
覆盖整个一年,从一月一日 00:00:00开始,到十二月三十一日 23:59:59结束。
// create instance representing the current year $currentYear = new Year(); // creates instance representing the year 2015 $year2015 = new Year(2015);
额外方法
months()
:返回一个迭代器,包含该年的所有stubbles\dates\span\Month
实例isLeapYear()
:检查年份是否是闰年isCurrentYear()
:检查年份是否代表当前年份
stubbles\dates\span\CustomDatespan
覆盖自定义日期范围,从给定日期的00:00:00开始,到给定日期的23:59:59结束。
// create a span from 2006-04-04 00:00:00 to 2006-04-20 23:59:59 $custom = new CustomDatespan('2006-04-04', '2006-04-20');
构造函数参数接受所有Date::castFrom()
接受的值,见上文。请注意,开始时间总是设置为00:00:00,结束时间总是设置为23:59:59。无法更改为其他时间。
与bovigo/assert集成
如果您想对代码进行单元测试并需要测试日期相等性,可以使用bovigo/assert进行断言。stubbles/date提供了一个谓词stubbles\date\assert\equalsDate()
,可以用来检查日期的相等性。它可以接受stubbles\date\Date
接受的任何参数,并比较Unix时间戳与实际值。如果它们不指向同一时间点,错误信息将包含一个diff,以人类可读的形式显示两个日期。