Chronos

Chronos 提供了一个无依赖的 DateTimeImmutable 扩展,日期专用和时间专用类

  • Cake\Chronos\Chronos 扩展了 DateTimeImmutable 并提供许多辅助工具。

  • Cake\Chronos\ChronosDate 表示不受时间或时区影响的日历日期。

  • Cake\Chronos\ChronosTime 表示独立于日期或时区的时钟时间。

  • 只有安全的,不可变的对象。

  • 一个可插拔的翻译系统。库中只包含英文翻译。但是,可以使用 cakephp/i18n 来获得完整语言支持。

Chronos 类扩展了 DateTimeImmutable 并实现了 DateTimeInterface ,允许用户使用支持任一种类型的类型声明。

ChronosDateChronosTime 不扩展 DateTimeImmutable 并且不共享接口。但是,它们可以使用 toDateTimeImmutable() 转换为 DateTimeImmutable 实例。

安装

要安装 Chronos,您应该使用 composer 。从您的应用程序的 ROOT 目录(composer.json 文件所在的目录)运行以下命令

php composer.phar require "cakephp/chronos:^3.0"

创建实例

有许多方法可以获取 Chronos 或 Date 的实例。有很多工厂方法可以处理不同的参数集

use Cake\Chronos\Chronos;

$now = Chronos::now();
$today = Chronos::today();
$yesterday = Chronos::yesterday();
$tomorrow = Chronos::tomorrow();

// Parse relative expressions
$date = Chronos::parse('+2 days, +3 hours');

// Date and time integer values.
$date = Chronos::create(2015, 12, 25, 4, 32, 58);

// Date or time integer values.
$date = Chronos::createFromDate(2015, 12, 25);
$date = Chronos::createFromTime(11, 45, 10);

// Parse formatted values.
$date = Chronos::createFromFormat('m/d/Y', '06/15/2015');

使用不可变对象

Chronos 只提供不可变对象。

如果您使用过 PHP 的 DateTimeImmutableDateTime 类,那么您理解可变不可变对象之间的区别。

不可变对象每次更改时都会创建对象的副本。由于日期时间周围的修改方法并不总是很容易识别,因此数据可能会意外地修改或在开发人员不知情的情况下修改。不可变对象可以防止意外更改数据,并使代码免受基于顺序的依赖性问题。不可变性确实意味着您需要记住在使用修改器时替换变量

// This code doesn't work with immutable objects
$chronos->addDay(1);
doSomething($chronos);
return $chronos;

// This works like you'd expect
$chronos = $chronos->addDay(1);
$chronos = doSomething($chronos);
return $chronos;

通过捕获每次修改的返回值,您的代码将按预期工作。

日期对象

PHP 只提供将日期和时间部分结合在一起的日期时间类。用 DateTimeImmutable 表示日历日期可能有点笨拙,因为它包含时间和时区,而这些时区不属于“日期”。Chronos 提供了 ChronosDate ,允许您表示日期。这些对象的这些对象的时间始终固定为 00:00:00 并且不受服务器时区或修改帮助程序的影响

use Cake\Chronos\ChronosDate;

$today = ChronosDate::today();

// Changes to the time/timezone are ignored.
$today->modify('+1 hours');

// Outputs '2015-12-20'
echo $today;

虽然 ChronosDate 在内部使用固定的时区,但您可以指定要用于当前时间的时区,例如 now()today()

use Cake\Chronos\ChronosDate:

// Takes the current date from Asia/Tokyo time zone
$today = ChronosDate::today('Asia/Tokyo');

修改方法

Chronos 对象提供了修改方法,让您以细粒度的方式修改值

// Set components of the datetime value.
$halloween = Chronos::create()
    ->year(2015)
    ->month(10)
    ->day(31)
    ->hour(20)
    ->minute(30);

您还可以相对地修改日期时间的各个部分

$future = Chronos::create()
    ->addYears(1)
    ->subMonths(2)
    ->addDays(15)
    ->addHours(20)
    ->subMinutes(2);

还可以跳到时间中的定义点

$time = Chronos::create();
$time->startOfDay();
$time->endOfDay();
$time->startOfMonth();
$time->endOfMonth();
$time->startOfYear();
$time->endOfYear();
$time->startOfWeek();
$time->endOfWeek();

或跳到一周中的特定日期

$time->next(Chronos::TUESDAY);
$time->previous(Chronos::MONDAY);

在跨越 DST 转换修改日期/时间时,您的操作可能会增加/减少一个小时,从而导致小时值加起来不正确。您可以通过先将时区更改为 UTC ,然后修改时间来避免这些问题

// Additional hour gained.
$time = new Chronos('2014-03-30 00:00:00', 'Europe/London');
debug($time->modify('+24 hours')); // 2014-03-31 01:00:00

// First switch to UTC, and modify
$time = $time->setTimezone('UTC')
    ->modify('+24 hours');

修改完时间后,您可以添加原始时区以获取本地化时间。

比较方法

拥有 2 个 Chronos 日期/时间对象实例后,您可以通过多种方式比较它们

// Full suite of comparators exist
// equals, notEquals, greaterThan, greaterThanOrEquals, lessThan, lessThanOrEquals
$first->equals($second);
$first->greaterThanOrEquals($second);

// See if the current object is between two others.
$now->between($start, $end);

// Find which argument is closest or farthest.
$now->closest($june, $november);
$now->farthest($june, $november);

您也可以查询给定值在日历上的位置

$now->isToday();
$now->isYesterday();
$now->isFuture();
$now->isPast();

// Check the day of the week
$now->isWeekend();

// All other weekday methods exist too.
$now->isMonday();

您还可以了解一个值是否在一个相对的时间段内

$time->wasWithinLast('3 days');
$time->isWithinNext('3 hours');

生成差异

除了比较日期时间之外,计算两个值之间的差异或增量也是一项常见任务

// Get a DateInterval representing the difference
$first->diff($second);

// Get difference as a count of specific units.
$first->diffInHours($second);
$first->diffInDays($second);
$first->diffInWeeks($second);
$first->diffInYears($second);

您可以生成适合在提要或时间轴中使用的可读差异

// Difference from now.
echo $date->diffForHumans();

// Difference from another point in time.
echo $date->diffForHumans($other); // 1 hour ago;

格式化字符串

Chronos 提供了许多方法来显示或输出日期时间对象

// Uses the format controlled by setToStringFormat()
echo $date;

// Different standard formats
echo $time->toAtomString();      // 1975-12-25T14:15:16-05:00
echo $time->toCookieString();    // Thursday, 25-Dec-1975 14:15:16 EST
echo $time->toIso8601String();   // 1975-12-25T14:15:16-05:00
echo $time->toRfc822String();    // Thu, 25 Dec 75 14:15:16 -0500
echo $time->toRfc850String();    // Thursday, 25-Dec-75 14:15:16 EST
echo $time->toRfc1036String();   // Thu, 25 Dec 75 14:15:16 -0500
echo $time->toRfc1123String();   // Thu, 25 Dec 1975 14:15:16 -0500
echo $time->toRfc2822String();   // Thu, 25 Dec 1975 14:15:16 -0500
echo $time->toRfc3339String();   // 1975-12-25T14:15:16-05:00
echo $time->toRssString();       // Thu, 25 Dec 1975 14:15:16 -0500
echo $time->toW3cString();       // 1975-12-25T14:15:16-05:00

// Get the quarter/week
echo $time->toQuarter();         // 4
echo $time->toWeek();            // 52

// Generic formatting
echo $time->toTimeString();           // 14:15:16
echo $time->toDateString();           // 1975-12-25
echo $time->toDateTimeString();       // 1975-12-25 14:15:16
echo $time->toFormattedDateString();  // Dec 25, 1975
echo $time->toDayDateTimeString();    // Thu, Dec 25, 1975 2:15 PM

提取日期组件

获取日期对象的各个部分可以通过直接访问属性来完成

$time = new Chronos('2015-12-31 23:59:58.123');
$time->year;    // 2015
$time->month;   // 12
$time->day;     // 31
$time->hour     // 23
$time->minute   // 59
$time->second   // 58
$time->micro    // 123

其他可以访问的属性是

  • 时区

  • 时区名称

  • 星期几

  • 月份中的第几天

  • 一年中的第几天

  • 一个月的天数

  • 时间戳

  • 季度

  • 半年

测试辅助

编写单元测试时,固定当前时间很有帮助。Chronos 允许您为每个类固定当前时间。作为测试套件引导过程的一部分,您可以包含以下内容

Chronos::setTestNow(Chronos::now());
ChronosDate::setTestNow(ChronosDate::parse(Chronos::now()));

这将把所有对象的当前时间固定为测试套件开始时的点。

例如,如果您将 Chronos 固定到过去的某个时间点,则使用 now 或相对时间字符串创建的任何新的 Chronos 实例,都将相对于固定时间返回

Chronos::setTestNow(new Chronos('1975-12-25 00:00:00'));

$time = new Chronos(); // 1975-12-25 00:00:00
$time = new Chronos('1 hour ago'); // 1975-12-24 23:00:00

要重置固定,只需再次调用 setTestNow() ,不带参数或使用 null 作为参数。