DateTime 类
PHP 的 DateTime 类是处理日期和时间的核心面向对象接口。它提供了创建、修改、比较和格式化日期时间的完整 API,比传统的 date() 和 strtotime() 函数更加灵活和强大。PHP 8.2+ 对 DateTimeImmutable 做了多项改进。
前置知识
阅读本节前,建议先了解:PHP 面向对象编程、字符串处理
基础概念
DateTime vs DateTimeImmutable
php
<?php
declare(strict_types=1);
// DateTime - 可变对象(修改时改变自身)
$dt = new DateTime('2024-01-15');
$dt->modify('+1 day');
echo $dt->format('Y-m-d') . PHP_EOL; // 2024-01-16
// DateTimeImmutable - 不可变对象(修改时返回新对象)
$dti = new DateTimeImmutable('2024-01-15');
$newDt = $dti->modify('+1 day');
echo $dti->format('Y-m-d') . PHP_EOL; // 2024-01-15(不变)
echo $newDt->format('Y-m-d') . PHP_EOL; // 2024-01-16
// PHP 8.2+ 推荐使用 DateTimeImmutable
// 因为不可变对象更安全,避免意外的副作用创建 DateTime
构造方式
php
<?php
declare(strict_types=1);
// 1. 当前时间
$now = new DateTime();
$nowImmutable = new DateTimeImmutable();
// 2. 从字符串创建
$dt = new DateTime('2024-01-15 14:30:00');
$dt = new DateTime('2024-01-15');
$dt = new DateTime('tomorrow');
$dt = new DateTime('next monday');
$dt = new DateTime('last day of next month');
// 3. 从时间戳创建
$dt = DateTime::createFromFormat('U', (string) time());
$dt = new DateTime('@' . time()); // @ 前缀表示 Unix 时间戳
// 4. 从指定格式创建
$dt = DateTime::createFromFormat('Y-m-d H:i:s', '2024-01-15 14:30:00');
// 5. createFromImmutable / createFromMutable
$immutable = new DateTimeImmutable('2024-01-15');
$mutable = DateTime::createFromMutable($immutable->toMutable());
$mutable = new DateTime('2024-01-15');
$immutable = DateTimeImmutable::createFromMutable($mutable);createFromFormat 详细用法
php
<?php
declare(strict_types=1);
// 解析各种格式的日期字符串
$formats = [
['d/m/Y', '15/01/2024'], // 15/01/2024
['Y年m月d日', '2024年1月15日'], // 中文日期
['Ymd', '20240115'], // 紧凑格式
['d M Y', '15 Jan 2024'], // 英文缩写
];
foreach ($formats as [$format, $string]) {
$dt = DateTime::createFromFormat($format, $string);
if ($dt !== false) {
echo "{$string} => " . $dt->format('Y-m-d') . PHP_EOL;
}
}
// createFromFormat 时区参数
$dt = DateTime::createFromFormat(
'Y-m-d H:i:s',
'2024-01-15 14:30:00',
new DateTimeZone('Asia/Shanghai')
);
// 解析时获取错误信息
$date = DateTime::createFromFormat('Y-m-d', '2024-13-45');
if ($date === false) {
$errors = DateTime::getLastErrors();
print_r($errors);
}格式化输出
format() 方法
php
<?php
declare(strict_types=1);
$dt = new DateTime('2024-01-15 14:30:45');
echo $dt->format('Y-m-d H:i:s') . PHP_EOL; // 2024-01-15 14:30:45
echo $dt->format('Y/m/d') . PHP_EOL; // 2024/01/15
echo $dt->format('d.m.Y') . PHP_EOL; // 15.01.2024
echo $dt->format('F j, Y') . PHP_EOL; // January 15, 2024
echo $dt->format('c') . PHP_EOL; // ISO 8601: 2024-01-15T14:30:45+00:00
echo $dt->format('r') . PHP_EOL; // RFC 2822: Mon, 15 Jan 2024 14:30:45 +0000
echo $dt->format('U') . PHP_EOL; // Unix 时间戳
echo $dt->format('\\本\\日是第 W 周') . PHP_EOL; // 今日是第 03 周
// 常用格式字符:
// Y - 4位年份 m - 2位月份 d - 2位日期
// H - 24小时制 i - 分钟 s - 秒
// w - 周几(0-6) W - 年中第几周
// z - 年中第几天 t - 月份天数
// L - 是否闰年修改日期
modify() 方法
php
<?php
declare(strict_types=1);
$dt = new DateTime('2024-01-15');
// 相对时间修改
echo $dt->modify('+1 day')->format('Y-m-d') . PHP_EOL; // 2024-01-16
echo $dt->modify('-1 week')->format('Y-m-d') . PHP_EOL; // 2024-01-08
echo $dt->modify('+2 months')->format('Y-m-d') . PHP_EOL; // 2024-03-15
echo $dt->modify('+1 year')->format('Y-m-d') . PHP_EOL; // 2025-01-15
echo $dt->modify('next monday')->format('Y-m-d') . PHP_EOL;
echo $dt->modify('last day of this month')->format('Y-m-d') . PHP_EOL;
echo $dt->modify('first day of next month')->format('Y-m-d') . PHP_EOL;
// 注意:DateTime 的 modify 修改自身
// DateTimeImmutable 返回新对象add() / sub() 方法
php
<?php
declare(strict_types=1);
$dt = new DateTimeImmutable('2024-01-15');
// 使用 DateInterval
$interval = new DateInterval('P1Y2M3D'); // 1年2月3天
echo $dt->add($interval)->format('Y-m-d') . PHP_EOL; // 2025-03-18
$interval = DateInterval::createFromDateString('-6 months');
echo $dt->add($interval)->format('Y-m-d') . PHP_EOL;
// sub() 减去间隔
$dt2 = $dt->sub(new DateInterval('P10D'));
echo $dt2->format('Y-m-d') . PHP_EOL; // 2024-01-05
// setTimestamp
$dt3 = $dt->setTimestamp(1700000000);
echo $dt3->format('Y-m-d H:i:s') . PHP_EOL;比较日期
php
<?php
declare(strict_types=1);
$dt1 = new DateTime('2024-01-15');
$dt2 = new DateTime('2024-03-20');
// diff() - 计算两个日期的差值
$diff = $dt1->diff($dt2);
echo "差异: {$diff->y}年 {$diff->m}月 {$diff->d}天" . PHP_EOL;
echo "总天数: " . $diff->days . PHP_EOL;
echo "是否反转: " . ($diff->invert ? '是' : '否') . PHP_EOL;
// compare() - 比较两个日期
// PHP 8.2+ DateTimeImmutable::compare
$cmp = DateTimeImmutable::compare(
new DateTimeImmutable('2024-01-15'),
new DateTimeImmutable('2024-03-20')
);
echo "比较结果: {$cmp}" . PHP_EOL; // -1 (第一个小于第二个)
// 手动比较
if ($dt1 < $dt2) {
echo "dt1 在 dt2 之前" . PHP_EOL;
}
if ($dt1 > $dt2) {
echo "dt1 在 dt2 之后" . PHP_EOL;
}
if ($dt1 == $dt2) {
echo "dt1 和 dt2 相同" . PHP_EOL;
}实战示例
日期工具类
php
<?php
declare(strict_types=1);
class DateHelper
{
/**
* 判断是否为工作日
*/
public static function isWeekday(DateTimeInterface $dt): bool
{
return (int) $dt->format('N') <= 5;
}
/**
* 获取两个日期之间的工作日数
*/
public static function weekdaysBetween(
DateTimeInterface $start,
DateTimeInterface $end
): int {
$count = 0;
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
foreach ($period as $day) {
if (self::isWeekday($day)) {
$count++;
}
}
return $count;
}
/**
* 获取某月的天数
*/
public static function daysInMonth(int $year, int $month): int
{
return (int) (new DateTimeImmutable("{$year}-{$month}-01"))
->format('t');
}
/**
* 获取年龄
*/
public static function calculateAge(DateTimeInterface $birthday): int
{
return $birthday->diff(new DateTimeImmutable())->y;
}
}注意事项
- PHP 8.2+ 推荐使用
DateTimeImmutable DateTime::compare()(PHP 8.2+) 用于安全的日期比较modify()中使用next/last/this关键字可以方便地操作日期- 时区处理见 DateTimeZone
下一节
继续学习:DateInterval