日期和时间

class Cake\I18n\DateTime

如果您需要 TimeHelper 功能在 View 之外使用,请使用 DateTime

use Cake\I18n\DateTime;

class UsersController extends AppController
{
    public function initialize(): void
    {
        parent::initialize();
        $this->loadComponent('Authentication.Authentication');
    }

    public function afterLogin()
    {
        $identity = $this->Authentication->getIdentity();
        $time = new DateTime($identity->date_of_birth);
        if ($time->isToday()) {
            // Greet user with a happy birthday message
            $this->Flash->success(__('Happy birthday to you...'));
        }
    }
}

CakePHP 在幕后使用 Chronos 为其 DateTime 实用程序提供支持。任何您可以使用 Chronos 和 PHP 的 DateTimeImmutable 做的事情,您都可以使用 DateTime 做。

有关 Chronos 的更多详细信息,请参阅 API 文档.

创建 DateTime 实例

DateTime 是不可变对象,因为不可变性可以防止意外更改数据,并避免基于顺序的依赖项问题。

有几种方法可以创建 DateTime 实例

use Cake\I18n\DateTime;

// Create from a string datetime.
$time = DateTime::createFromFormat(
    'Y-m-d H:i:s',
    '2021-01-31 22:11:30',
    'America/New_York'
);

// Create from a timestamp and set timezone
$time = DateTime::createFromTimestamp(1612149090, 'America/New_York');

// Get the current time.
$time = DateTime::now();

// Or just use 'new'
$time = new DateTime('2021-01-31 22:11:30', 'America/New_York');

$time = new DateTime('2 hours ago');

DateTime 类构造函数可以接受内部 DateTimeImmutable PHP 类可以接受的任何参数。传递数字或数字字符串时,它将被解释为 UNIX 时间戳。

在测试用例中,您可以使用 setTestNow() 模拟 now()

// Fixate time.
$time = new DateTime('2021-01-31 22:11:30');
DateTime::setTestNow($time);

// Outputs '2021-01-31 22:11:30'
$now = DateTime::now();
echo $now->i18nFormat('yyyy-MM-dd HH:mm:ss');

// Outputs '2021-01-31 22:11:30'
$now = DateTime::parse('now');
echo $now->i18nFormat('yyyy-MM-dd HH:mm:ss');

操作

请记住,DateTime 实例始终从 setter 返回一个新实例,而不是修改自身

$time = DateTime::now();

// Create and reassign a new instance
$newTime = $time->year(2013)
    ->month(10)
    ->day(31);
// Outputs '2013-10-31 22:11:30'
echo $newTime->i18nFormat('yyyy-MM-dd HH:mm:ss');

您还可以使用 PHP 内置 DateTime 类提供的方法

$time = $time->setDate(2013, 10, 31);

未能重新分配新的 DateTime 实例将导致使用原始的未修改实例

$time->year(2013)
    ->month(10)
    ->day(31);
// Outputs '2021-01-31 22:11:30'
echo $time->i18nFormat('yyyy-MM-dd HH:mm:ss');

您可以通过减去和添加其组件来创建另一个具有修改日期的实例

$time = DateTime::create(2021, 1, 31, 22, 11, 30);
$newTime = $time->subDays(5)
    ->addHours(-2)
    ->addMonth(1);
// Outputs '2/26/21, 8:11 PM'
echo $newTime;

// Using strtotime strings.
$newTime = $time->modify('+1 month -5 days -2 hours');
// Outputs '2/26/21, 8:11 PM'
echo $newTime;

您可以通过访问日期的属性来获取其内部组件

$time = DateTime::create(2021, 1, 31, 22, 11, 30);
echo $time->year; // 2021
echo $time->month; // 1
echo $time->day; // 31
echo $time->timezoneName; // America/New_York

格式化

static Cake\I18n\DateTime::setJsonEncodeFormat($format)

此方法设置将对象转换为 JSON 时使用的默认格式

DateTime::setJsonEncodeFormat('yyyy-MM-dd HH:mm:ss');  // For any immutable DateTime
Date::setJsonEncodeFormat('yyyy-MM-dd HH:mm:ss');  // For any mutable Date

$time = DateTime::parse('2021-01-31 22:11:30');
echo json_encode($time);   // Outputs '2021-01-31 22:11:30'

Date::setJsonEncodeFormat(static function($time) {
    return $time->format(DATE_ATOM);
});

注意

此方法必须以静态方式调用。

注意

请注意,这不是 PHP Datetime 字符串格式!您需要使用 ICU 日期格式字符串,如以下资源中所指定:https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax.

Changed in version 4.1.0: 添加了 callable 参数类型。

Cake\I18n\DateTime::i18nFormat($format = null, $timezone = null, $locale = null)

使用 Time 实例最常见的事情之一是打印出格式化的日期。CakePHP 使这变得轻而易举

$time = DateTime::parse('2021-01-31 22:11:30');

// Prints a localized datetime stamp. Outputs '1/31/21, 10:11 PM'
echo $time;

// Outputs '1/31/21, 10:11 PM' for the en-US locale
echo $time->i18nFormat();

// Use the full date and time format. Outputs 'Sunday, January 31, 2021 at 10:11:30 PM Eastern Standard Time'
echo $time->i18nFormat(\IntlDateFormatter::FULL);

// Use full date but short time format. Outputs 'Sunday, January 31, 2021 at 10:11 PM'
echo $time->i18nFormat([\IntlDateFormatter::FULL, \IntlDateFormatter::SHORT]);

// Outputs '2021-Jan-31 22:11:30'
echo $time->i18nFormat('yyyy-MMM-dd HH:mm:ss');

可以指定要显示的字符串的所需格式。您可以将 IntlDateFormatter 常量 作为此函数的第一个参数传递,或者传递完整的 ICU 日期格式字符串,如以下资源中所指定:https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax.

您也可以使用非格里高利历格式化日期

// On ICU version 66.1
$time = DateTime::create(2021, 1, 31, 22, 11, 30);

// Outputs 'Sunday, Bahman 12, 1399 AP at 10:11:30 PM Eastern Standard Time'
echo $time->i18nFormat(\IntlDateFormatter::FULL, null, 'en-IR@calendar=persian');

// Outputs 'Sunday, January 31, 3 Reiwa at 10:11:30 PM Eastern Standard Time'
echo $time->i18nFormat(\IntlDateFormatter::FULL, null, 'en-JP@calendar=japanese');

// Outputs 'Sunday, Twelfth Month 19, 2020(geng-zi) at 10:11:30 PM Eastern Standard Time'
echo $time->i18nFormat(\IntlDateFormatter::FULL, null, 'en-CN@calendar=chinese');

// Outputs 'Sunday, Jumada II 18, 1442 AH at 10:11:30 PM Eastern Standard Time'
echo $time->i18nFormat(\IntlDateFormatter::FULL, null, 'en-SA@calendar=islamic');

支持以下日历类型

  • japanese

  • buddhist

  • chinese

  • persian

  • indian

  • islamic

  • hebrew

  • coptic

  • ethiopic

注意

对于常量字符串,例如 IntlDateFormatter::FULL,Intl 使用 ICU 库,该库从 CLDR(https://cldr.unicode.org/)获取其数据,CLDR 的版本可能因 PHP 安装而异,并产生不同的结果。

Cake\I18n\DateTime::nice()

打印出预定义的“好”格式

$time = DateTime::parse('2021-01-31 22:11:30', new \DateTimeZone('America/New_York'));

// Outputs 'Jan 31, 2021, 10:11 PM' in en-US
echo $time->nice();

您可以更改显示日期的时区,而无需更改 DateTime 对象本身。当您将日期存储在一个时区中,但希望以用户的时区显示时,这很有用

// Outputs 'Monday, February 1, 2021 at 4:11:30 AM Central European Standard Time'
echo $time->i18nFormat(\IntlDateFormatter::FULL, 'Europe/Paris');

// Outputs 'Monday, February 1, 2021 at 12:11:30 PM Japan Standard Time'
echo $time->i18nFormat(\IntlDateFormatter::FULL, 'Asia/Tokyo');

// Timezone is unchanged. Outputs 'America/New_York'
echo $time->timezoneName;

将第一个参数保留为 null 将使用默认格式字符串

// Outputs '2/1/21, 4:11 AM'
echo $time->i18nFormat(null, 'Europe/Paris');

最后,可以使用不同的区域设置来显示日期

// Outputs 'lundi 1 février 2021 à 04:11:30 heure normale d’Europe centrale'
echo $time->i18nFormat(\IntlDateFormatter::FULL, 'Europe/Paris', 'fr-FR');

// Outputs '1 févr. 2021 à 04:11'
echo $time->nice('Europe/Paris', 'fr-FR');

设置默认区域设置和格式字符串

使用 nice i18nFormat 时显示日期的默认区域设置取自指令 intl.default_locale。但是,您可以在运行时修改此默认值

DateTime::setDefaultLocale('es-ES');
Date::setDefaultLocale('es-ES');

// Outputs '31 ene. 2021 22:11'
echo $time->nice();

从现在开始,日期时间将以西班牙语首选格式显示,除非在格式化方法中直接指定了不同的区域设置。

同样,可以更改用于 i18nFormat 的默认格式字符串

DateTime::setToStringFormat(\IntlDateFormatter::SHORT); // For any DateTime
Date::setToStringFormat(\IntlDateFormatter::SHORT); // For any Date

// The same method exists on Date, and DateTime
DateTime::setToStringFormat([
    \IntlDateFormatter::FULL,
    \IntlDateFormatter::SHORT
]);
// Outputs 'Sunday, January 31, 2021 at 10:11 PM'
echo $time;

// The same method exists on Date and DateTime
DateTime::setToStringFormat("EEEE, MMMM dd, yyyy 'at' KK:mm:ss a");
// Outputs 'Sunday, January 31, 2021 at 10:11:30 PM'
echo $time;

建议始终使用常量,而不是直接传递日期格式字符串。

注意

请注意,这不是 PHP Datetime 字符串格式!您需要使用 ICU 日期格式字符串,如以下资源中所指定:https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax.

格式化相对时间

Cake\I18n\DateTime::timeAgoInWords(array $options = [])

通常,打印相对于现在的时期非常有用

$time = new DateTime('Jan 31, 2021');
// On June 12, 2021, this would output '4 months, 1 week, 6 days ago'
echo $time->timeAgoInWords(
    ['format' => 'MMM d, YYY', 'end' => '+1 year']
);

end 选项允许您定义在哪个时间点之后,相对时间应使用 format 选项进行格式化。 accuracy 选项允许我们控制每个间隔范围应使用什么级别的细节

// Outputs '4 months ago'
echo $time->timeAgoInWords([
    'accuracy' => ['month' => 'month'],
    'end' => '1 year'
]);

通过将accuracy设置为字符串,您可以指定所需的输出详细程度。

$time = new DateTime('+23 hours');
// Outputs 'in about a day'
echo $time->timeAgoInWords([
    'accuracy' => 'day'
]);

转换

Cake\I18n\DateTime::toQuarter()

创建后,您可以将DateTime实例转换为时间戳或季度值。

$time = new DateTime('2021-01-31');
echo $time->toQuarter();  // Outputs '1'
echo $time->toUnixString();  // Outputs '1612069200'

与当前时间比较

Cake\I18n\DateTime::isYesterday()
Cake\I18n\DateTime::isThisWeek()
Cake\I18n\DateTime::isThisMonth()
Cake\I18n\DateTime::isThisYear()

您可以通过多种方式将DateTime实例与当前时间进行比较。

$time = new DateTime('+3 days');

debug($time->isYesterday());
debug($time->isThisWeek());
debug($time->isThisMonth());
debug($time->isThisYear());

上述每个方法将根据DateTime实例是否与当前时间匹配返回true/false

与时间间隔比较

Cake\I18n\DateTime::isWithinNext($interval)

您可以使用wasWithinLast()isWithinNext()查看DateTime实例是否落在给定范围内。

$time = new DateTime('+3 days');

// Within 2 days. Outputs 'false'
debug($time->isWithinNext('2 days'));

// Within 2 next weeks. Outputs 'true'
debug($time->isWithinNext('2 weeks'));
Cake\I18n\DateTime::wasWithinLast($interval)

您还可以比较过去范围内DateTime实例。

$time = new DateTime('-72 hours');

// Within past 2 days. Outputs 'false'
debug($time->wasWithinLast('2 days'));

// Within past 3 days. Outputs 'true'
debug($time->wasWithinLast('3 days'));

// Within past 2 weeks. Outputs 'true'
debug($time->wasWithinLast('2 weeks'));

日期

class Cake\I18n\Date

CakePHP 中的不可变Date类表示不受时间和时区影响的日历日期。Date类封装了Cake\\Chronos\\ChronosDate类。

注意

DateTime类不同,Date不扩展DateTimeInterface。因此您无法直接比较Date实例与DateTime实例。但您可以进行如下比较:$dateTime->toNative() > $date->toNative()

时间

class Cake\I18n\Time

Time类表示独立于日期或时区的时钟时间。类似于DateTime`Date类,Time类也是不可变的。它封装了Cake\\Chronos\\ChronosTime类。

接受本地化请求数据

在创建操作日期的文本输入时,您可能希望接受和解析本地化日期时间字符串。请参阅解析本地化日期时间数据

支持的时区

CakePHP 支持所有有效的 PHP 时区。有关支持的时区列表,请参阅此页面